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



The information in this article applies to:

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

This article was previously published under Q294140

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.

CAUSE

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

STATUS

This problem was corrected in MDAC version 2.6.

MORE INFORMATION

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

Steps to reproduce behavior

  1. Create a new Visual C++ Console application and paste the following code into a .cpp file:
    
    #include <iostream.h>
    #include <windows.h>
    #include <SQL.h>
    #include <SQLEXT.h>
    #include <ODBCINST.h>
    #include <stdio.h>
    #include <process.h>
    #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	<< "Enter number of worker threads:";
    	cin		>> g_dwWorkerThreads;
    
    	cout	<< "Enter no of iterations:";
    	cin		>> g_dwIterations;
    
    	int nDelay = 0;
    	cout	<< "Delay:";
    	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("Creating thread<%d><%d>\n", i, dwThreadId);
    		
    		if ( nDelay > 0 )
    		{
    			Sleep(nDelay); 
    		}
    	
    	}
    	
    	printf("Waiting for worker threads to finish\n");
    
    	
    	mydata= WaitForMultipleObjects(g_dwWorkerThreads,pThreadHandles,TRUE,INFINITE);
    
    	printf("Done waiting for worker threads to finish!\n");
    	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("Allocating connection handle failed");
    				break;
    			}
    	
    			sprintf(	tConnectionStringIn,  
    						"DRIVER={SQL Server};SERVER=%s;UID=%s;PWD=%s;DATABASE=%s;APP=%s",
    						"TestMSSQLServer", "sa","","pubs","pooltest");
    		         sprintf(buffer,"This is thread 0x%08x. before SQLDriverconnect .\n",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, "SQLConnect() Failed\n\n");
    	   	           break;
    		         }
    	
    
    			sprintf(buffer,"This is thread 0x%08x.after  SQLDriverConnect \n",GetCurrentThreadId());
    		         OutputDebugString(buffer);
    
    
    			SQLDisconnect(m_hdbc);	
    			sprintf(buffer,"This is thread 0x%08x.after SQLDisconnect\n",GetCurrentThreadId());
           		         OutputDebugString(buffer);
    
    			SQLFreeHandle(SQL_HANDLE_DBC, m_hdbc);	
    			sprintf(buffer,"This is thread 0x%08x. after SQLFreeHandle dbc\n",GetCurrentThreadId());
    			OutputDebugString(buffer);   
    	
    		} while ( FALSE );
    	}
    
    	printf("<%d>Done\n",GetCurrentThreadId());
    
    	return 100;
    }
    
    void ProcessLogMessages(SQLSMALLINT plm_handle_type, SQLHANDLE plm_handle,
    						char *logstring)
    {
    	RETCODE		plm_retcode = SQL_SUCCESS;
    	UCHAR		plm_szSqlState[MAXBUFLEN] = "",plm_szErrorMsg[MAXBUFLEN] = "";
    	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("szSqlState = %s\n",plm_szSqlState);
    			printf("pfNativeError = %d\n",plm_pfNativeError);
    			printf("szErrorMsg = %s\n",plm_szErrorMsg);
    			printf("pcbErrorMsg = %d\n\n",plm_pcbErrorMsg);
    		}
    		plm_cRecNmbr++;
    	} // end while
    }
    					
  2. Compile and run the project.

REFERENCES

For additional information on ODBC connection pooling, click the following article numbers to view the articles in the Microsoft Knowledge Base:

164221 How to enable connection pooling in an ODBC application

161634 Connection pooling requires same henv and driver

216950 How to enable ODBC connection pooling performance counters


Modification Type:MajorLast Reviewed:12/21/2004
Keywords:kbBug kbfix kbMDAC260fix KB294140 kbAudDeveloper