1
2 #ifndef _ERRORS_H_
3 #define _ERRORS_H_
4
5 // Sets an exception based on the ODBC SQLSTATE and error message and returns zero. If either handle is not available,
6 // pass SQL_NULL_HANDLE.
7 //
8 // conn
9 // The connection object, from which it will use the Unicode encoding. May be null if not available.
10 //
11 // szFunction
12 // The name of the function that failed. Python generates a useful stack trace, but we often don't know where in the
13 // C++ code we failed.
14 //
15 PyObject* RaiseErrorFromHandle(Connection *conn, const char* szFunction, HDBC hdbc, HSTMT hstmt);
16
17 // Sets an exception using a printf-like error message.
18 //
19 // szSqlState
20 // The optional SQLSTATE reported by ODBC. If not provided (sqlstate is NULL or sqlstate[0] is NULL), "HY000"
21 // (General Error) is used. Note that HY000 causes Error to be used if exc_class is not provided.
22 //
23 // exc_class
24 // The optional exception class (DatabaseError, etc.) to construct. If NULL, the appropriate class will be
25 // determined from the SQLSTATE.
26 //
27 PyObject* RaiseErrorV(const char* sqlstate, PyObject* exc_class, const char* format, ...);
28
29
30 // Constructs an exception and returns it.
31 //
32 // This function is like RaiseErrorFromHandle, but gives you the ability to examine the error first (in particular,
33 // used to examine the SQLSTATE using HasSqlState). If you want to use the error, call PyErr_SetObject(ex->ob_type,
34 // ex). Otherwise, dispose of the error using Py_DECREF(ex).
35 //
36 // conn
37 // The connection object, from which it will use the Unicode encoding. May be null if not available.
38 //
39 // szFunction
40 // The name of the function that failed. Python generates a useful stack trace, but we often don't know where in the
41 // C++ code we failed.
42 //
43 PyObject* GetErrorFromHandle(Connection *conn, const char* szFunction, HDBC hdbc, HSTMT hstmt);
44
45
46 // Returns true if `ex` is a database exception with SQLSTATE `szSqlState`. Returns false otherwise.
47 //
48 // It is safe to call with ex set to zero. The SQLSTATE comparison is case-insensitive.
49 //
50 bool HasSqlState(PyObject* ex, const char* szSqlState);
51
52
53 // Returns true if the HSTMT has a diagnostic record with the given SQLSTATE. This is used after SQLGetData call that
54 // returned SQL_SUCCESS_WITH_INFO to see if it also has SQLSTATE 01004, indicating there is more data.
55 //
56 bool HasSqlState(HSTMT hstmt, const char* szSqlState);
57
RaiseErrorFromException(PyObject * pError)58 inline PyObject* RaiseErrorFromException(PyObject* pError)
59 {
60 // PyExceptionInstance_Class doesn't exist in 2.4
61 #if PY_MAJOR_VERSION >= 3
62 PyErr_SetObject((PyObject*)Py_TYPE(pError), pError);
63 #else
64 PyObject* cls = (PyObject*)((PyInstance_Check(pError) ? (PyObject*)((PyInstanceObject*)pError)->in_class : (PyObject*)(Py_TYPE(pError))));
65 PyErr_SetObject(cls, pError);
66 #endif
67 return 0;
68 }
69
CopySqlState(const ODBCCHAR * src,char * dest)70 inline void CopySqlState(const ODBCCHAR* src, char* dest)
71 {
72 // Copies a SQLSTATE read as SQLWCHAR into a character buffer. We know that SQLSTATEs are
73 // composed of ASCII characters and we need one standard to compare when choosing
74 // exceptions.
75 //
76 // Strangely, even when the error messages are UTF-8, PostgreSQL and MySQL encode the
77 // sqlstate as UTF-16LE. We'll simply copy all non-zero bytes, with some checks for
78 // running off the end of the buffers which will work for ASCII, UTF8, and UTF16 LE & BE.
79 // It would work for UTF32 if I increase the size of the ODBCCHAR buffer to handle it.
80 //
81 // (In the worst case, if a driver does something totally weird, we'll have an incomplete
82 // SQLSTATE.)
83 //
84
85 const char* pchSrc = (const char*)src;
86 const char* pchSrcMax = pchSrc + sizeof(ODBCCHAR) * 5;
87 char* pchDest = dest; // Where we are copying into dest
88 char* pchDestMax = dest + 5; // We know a SQLSTATE is 5 characters long
89
90 while (pchDest < pchDestMax && pchSrc < pchSrcMax)
91 {
92 if (*pchSrc)
93 *pchDest++ = *pchSrc;
94 pchSrc++;
95 }
96 *pchDest = 0;
97 }
98
99 #endif // _ERRORS_H_
100