[This is preliminary documentation and subject to change.]
Since the ODBC Driver Manager is thread-safe, the adapter is inherently thread-safe.
The only exception to this is where an SQLCancel is invoked on synchronously executing the statement handle hStmt object from a different thread. The Driver Manager uses critical sections (non-reentrant pieces of code) on the environment handle hEnvs, the connection handle hDbcs, and hStmts to guarantee synchronous operation on these objects.
An action on one of these objects causes the Driver Manager to enter a critical section for that object. In the case of SQLCancel, the Driver Manager enters a "cancel-in-progress" critical section. This prevents SQLCancel from being reentered before the first one is completed. The adapter's SQLCancel is then invoked.
If there is no simultaneous action on the statement handle, the SQLCancel is treated as an SQLFreeStmt or SQL_CLOSE operation. The adapter returns SQL_SUCCESS_WITH_INFO with a SQLSTATE of 01S05. This causes the Driver Manager to return SQL_SUCCESS to the application.
If there was simultaneous action on the statement handle, the return code from the original thread's ODBC function determines if the SQLCancel was successful.
The adapter's SQLCancel is implemented as follows:
The ODBC 2.0 Programmer's Reference and SDK Guide suggests two techniques for writing thread-safe multithreaded ODBC applications:
The application must know which operations are being performed on an object. For example, if a thread does an SQLFetch on a statement handle, begins to process the data, and a second thread does an SQLFetch on the same statement handle into the same buffer, the first thread might get columns from the first row of the rowset mixed with columns from the second row.
Also, the application must be particularly careful in performing SQLFreeStmts. For example, if an application attempts to perform an operation on a statement handle that is being freed, it blocks on the statement handle. When it unblocks, it fails with an access violation because the statement handle no longer exists. The application must ensure that the statement handle is inactive before calling SQLFreeStmt, SQL_DROP, or SQLDisconnect.