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