Microsoft KB Archive/294140

= FIX: Connection pooling causes Windows 2000 computer with MDAC 25/2.5 SP1 to stop responding =

Article ID: 294140

Article Last Modified on 12/21/2004

-

APPLIES TO

 Microsoft Data Access Components 2.5, when used with:  Microsoft Windows 2000 Advanced Server

 Microsoft Windows 2000 Service Pack 1

 Microsoft Windows 2000 Service Pack 1  Microsoft Data Access Components 2.5 Service Pack 1, when used with:  Microsoft Windows 2000 Advanced Server</li></ul>

 Microsoft Windows 2000 Service Pack 1</li></ul>

 Microsoft Windows 2000 Service Pack 1</li></ul> </li></ul>

-

<div class="notice_section">

This article was previously published under Q294140

<div class="symptoms_section">

SYMPTOMS
When an application that uses multiple threads that share a global environment handle implements Open Database Connectivity (ODBC) connection pooling, the application may stop responding (hang) on the platforms listed above with MDAC version 2.5 or MDAC verion 2.5 Service Pack 1.

<div class="cause_section">

CAUSE
This problem is due to a bug in the Mtxdm.dll file that ships with MDAC 2.5 and 2.5 SP1.

<div class="status_section">

STATUS
This problem was corrected in MDAC version 2.6.

<div class="moreinformation_section">

MORE INFORMATION
This problem occurs regardless of the ODBC driver you are using and the datasource you are going against.

Steps to reproduce behavior
<ol>  Create a new Visual C++ Console application and paste the following code into a .cpp file:
 * 1) include <iostream.h>
 * 2) include <windows.h>
 * 3) include <SQL.h>
 * 4) include <SQLEXT.h>
 * 5) include <ODBCINST.h>
 * 6) include <stdio.h>
 * 7) include <process.h>
 * 8) define MAXBUFLEN 255

unsigned __stdcall TestPooling(LPVOID pParam); void   ProcessLogMessages(SQLSMALLINT plm_handle_type,                           SQLHANDLE plm_handle, char *logstring); HENV g_henv;

DWORD g_dwIterations = 10; DWORD g_dwWorkerThreads = 2;

int main(int argc, char **argv) {       DWORD mydata; SQLRETURN nSQLRetCode = SQLSetEnvAttr(SQL_NULL_HENV, SQL_ATTR_CONNECTION_POOLING, (void*)SQL_CP_ONE_PER_DRIVER, 0); nSQLRetCode = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HENV, &g_henv); nSQLRetCode = SQLSetEnvAttr(g_henv, SQL_ATTR_ODBC_VERSION, (SQLPOINTER)SQL_OV_ODBC3, SQL_IS_INTEGER); cout   << &quot;Enter number of worker threads:&quot;; cin    >> g_dwWorkerThreads;

cout   << &quot;Enter no of iterations:&quot;; cin    >> g_dwIterations;

int nDelay = 0; cout   << &quot;Delay:&quot;; cin    >> nDelay;

HANDLE *pThreadHandles = new HANDLE[g_dwWorkerThreads];

unsigned int dwThreadId = 0; for ( DWORD i = 0; i < g_dwWorkerThreads; i++) {       pThreadHandles[i] = (HANDLE)_beginthreadex(NULL,0,TestPooling, NULL, 0, &dwThreadId ); printf(&quot;Creating thread<%d><%d>\n&quot;, i, dwThreadId); if ( nDelay > 0 ) {           Sleep(nDelay); }   }    printf(&quot;Waiting for worker threads to finish\n&quot;);

mydata= WaitForMultipleObjects(g_dwWorkerThreads,pThreadHandles,TRUE,INFINITE);

printf(&quot;Done waiting for worker threads to finish!\n&quot;); getchar;

return (0); }

unsigned __stdcall TestPooling(LPVOID pParam) {   SQLRETURN nSQLRetCode = SQL_SUCCESS;

SQLHDBC    m_hdbc; char buffer[256]; TCHAR tConnectionStringIn[ 256 ], tConnStringOut[256]; SWORD  cLength = 0;    SDWORD  cbTemp = 0; SQLRETURN nRetCode =SQL_SUCCESS;

for ( DWORD i = 0; i < g_dwIterations; i++ ) {       do        { nSQLRetCode = SQLAllocHandle(SQL_HANDLE_DBC, g_henv, &m_hdbc); if ( SQL_ERROR == nSQLRetCode ) {               printf(&quot;Allocating connection handle failed&quot;); break; }           sprintf(    tConnectionStringIn,                          &quot;DRIVER={SQL Server};SERVER=%s;UID=%s;PWD=%s;DATABASE=%s;APP=%s&quot;,                        &quot;TestMSSQLServer&quot;, &quot;sa&quot;,&quot;&quot;,&quot;pubs&quot;,&quot;pooltest&quot;); sprintf(buffer,&quot;This is thread 0x%08x. before SQLDriverconnect .\n&quot;,GetCurrentThreadId); OutputDebugString(buffer);

nSQLRetCode = SQLDriverConnect(m_hdbc, NULL, (SQLTCHAR*) tConnectionStringIn,strlen( tConnectionStringIn ),                                                     (SQLTCHAR*) tConnStringOut,(SWORD)(sizeof(tConnStringOut)/sizeof(TCHAR)),                                                      &cLength, SQL_DRIVER_NOPROMPT);   //connect to the odbc if (nSQLRetCode == SQL_ERROR) {                   ProcessLogMessages(SQL_HANDLE_DBC, m_hdbc, &quot;SQLConnect Failed\n\n&quot;); break; }

sprintf(buffer,&quot;This is thread 0x%08x.after SQLDriverConnect \n&quot;,GetCurrentThreadId); OutputDebugString(buffer);

SQLDisconnect(m_hdbc); sprintf(buffer,&quot;This is thread 0x%08x.after SQLDisconnect\n&quot;,GetCurrentThreadId); OutputDebugString(buffer);

SQLFreeHandle(SQL_HANDLE_DBC, m_hdbc); sprintf(buffer,&quot;This is thread 0x%08x. after SQLFreeHandle dbc\n&quot;,GetCurrentThreadId); OutputDebugString(buffer); } while ( FALSE ); }

printf(&quot;<%d>Done\n&quot;,GetCurrentThreadId);

return 100; }

void ProcessLogMessages(SQLSMALLINT plm_handle_type, SQLHANDLE plm_handle,                       char *logstring) {   RETCODE     plm_retcode = SQL_SUCCESS; UCHAR      plm_szSqlState[MAXBUFLEN] = &quot;&quot;,plm_szErrorMsg[MAXBUFLEN] = &quot;&quot;; SDWORD     plm_pfNativeError = 0L; SWORD      plm_pcbErrorMsg = 0; SQLSMALLINT plm_cRecNmbr = 1;

printf(logstring);

while (plm_retcode != SQL_NO_DATA_FOUND) {       plm_retcode = SQLGetDiagRec(plm_handle_type, plm_handle,            plm_cRecNmbr, plm_szSqlState, &plm_pfNativeError,            plm_szErrorMsg, MAXBUFLEN - 1, &plm_pcbErrorMsg); if (plm_retcode != SQL_NO_DATA_FOUND) {           printf(&quot;szSqlState = %s\n&quot;,plm_szSqlState); printf(&quot;pfNativeError = %d\n&quot;,plm_pfNativeError); printf(&quot;szErrorMsg = %s\n&quot;,plm_szErrorMsg); printf(&quot;pcbErrorMsg = %d\n\n&quot;,plm_pcbErrorMsg); }       plm_cRecNmbr++; } // end while }                   </li> Compile and run the project.</li></ol>

<div class="references_section">