ADODB Command Memory Leak - Source Sample



I'm trying to find a memory leak in ADO code and have a sample that exhibits
the leak. I started with some sample code from Matt Neerincx (thank you) and
modified it to resemble the way it is executed in my program and a COM
component.

The test includes a loop which:
1. connects to the database (jet)
2. executes a command to delete records from a table
3. executes a command (3 times) to add a record to the table
4. disconnects

I've constructed the test using commands in stored procedures, and using
commands as text with and without parameters. The code is below. Can anyone
point out the leak?

Thanks.


#include "stdafx.h"
#include <atlbase.h>
//#include "Test2.h"
#include "conio.h"

#pragma warning( push )
#pragma warning( disable : 4146 )
#import "c:\Program Files\Common Files\system\ado\msadox.dll"
#import "c:\Program Files\Common Files\system\ado\msado15.dll"
rename("EOF","EndOfFile")
#pragma warning( pop )

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

//#define USE_CMDPROC
//#define USE_PARAMS

void RunSample();
ADODB::_ConnectionPtr GetJetConnection();
void RunSingleLoop();
void Reset(ADODB::_ConnectionPtr conn);
void AddRecords(ADODB::_ConnectionPtr conn);

/////////////////////////////////////////////////////////////////////////////
// The one and only application object

CWinApp theApp;

using namespace std;

int _tmain(int argc, TCHAR* argv[], TCHAR* envp[])
{
int nRetCode = 0;

// initialize MFC and print and error on failure
if (!AfxWinInit(::GetModuleHandle(NULL), NULL, ::GetCommandLine(), 0))
{
// TODO: change error code to suit your needs
cerr << _T("Fatal Error: MFC initialization failed") << endl;
return -1;
}

CoInitialize(NULL);
RunSample();
CoUninitialize();

return nRetCode;
}

#define LOOP_COUNT 100000 // Number of loops to execute.

void RunSample()
{

#if defined(USE_CMDPROC) && defined(USE_PARAMS)
#error ("Invalid configuration")
#endif

ADODB::_ConnectionPtr global_conn = NULL;
int i;

try
{
// Open global conn to keep Jet loaded (perf).
global_conn = GetJetConnection();

try
{
global_conn->Execute(L"drop table
T1",NULL,ADODB::adExecuteNoRecords|ADODB::adCmdText);
}
catch ( _com_error ex )
{

}

global_conn->Execute(L"create table T1(f1 int, f2
int)",NULL,ADODB::adExecuteNoRecords|ADODB::adCmdText);

for (i=1; i<=LOOP_COUNT; i++ )
{
RunSingleLoop();

Sleep(5);
if ( 0 == (i%1000))
{
printf( "Completed %08lu of %08lu iterations.\n", i, LOOP_COUNT );
while ( _kbhit() )
{
int x = _getch();
if ( 'Q' == x || 'q' == x )
{
return;
}
}
}
}
}

catch( _com_error ex )
{
// Robust error trapping left as an exercise for the reader. (G)
ASSERT(FALSE);
}

return;
}

_bstr_t JET_CONNECT(L"Provider=Microsoft.Jet.OLEDB.4.0;Data
Source=C:\\NW99.mdb;");

ADODB::_ConnectionPtr GetJetConnection()
{
HRESULT hr;
ADODB::_ConnectionPtr conn = NULL;

hr = conn.CreateInstance( __uuidof(ADODB::Connection) );
//if ( FAILED( hr ) ) throw( _com_error( hr, NULL ) );

conn->CursorLocation = ADODB::adUseServer;

// Open connection.
conn->Open( JET_CONNECT, "", "", -1L );
//Setting this property doesn't help.
//conn->Properties->Item["Jet OLEDB:Max Buffer Size"]->Value = 500L;

return conn;
}

void RunSingleLoop()
{
ADODB::_ConnectionPtr conn = NULL;

// Open local conn for loop.
conn = GetJetConnection();

Reset(conn);

// The AddRecords generate the memory leaks
AddRecords(conn);
AddRecords(conn);
AddRecords(conn);

conn->Close();
conn = NULL;
}

void Reset(ADODB::_ConnectionPtr conn)
{
ADODB::_CommandPtr cmd = NULL;
CComVariant v1;

HRESULT hr = cmd.CreateInstance( __uuidof(ADODB::Command) );

/*
Query: qdMissingData

PARAMETERS P1 Long;
DELETE * FROM T1 WHERE f1=P1;
*/

cmd->ActiveConnection = conn;
#ifdef USE_CMDPROC
cmd->CommandText = L"qdMissingData";
cmd->CommandType = ADODB::adCmdStoredProc;
#else
#ifdef USE_PARAMS
cmd->CommandText = L"DELETE * FROM T1 WHERE f1=?";
#else
cmd->CommandText = L"DELETE * FROM T1 WHERE f1=1";
#endif
cmd->CommandType = ADODB::adCmdText;
#endif

#ifdef USE_PARAMS
v1 = 1L;
cmd->Parameters->Append(cmd->CreateParameter(
L"P1",ADODB::adInteger,ADODB::adParamInput,-1, v1));
v1.Clear();
#endif

cmd->Execute(NULL,NULL,ADODB::adExecuteNoRecords);

cmd->ActiveConnection = NULL;
cmd = NULL;
}

void AddRecords(ADODB::_ConnectionPtr conn)
{
ADODB::_CommandPtr cmd = NULL;
CComVariant v1;
CComVariant v2;
static long lCounter = 1;

// Now create parameterized ADO call.
HRESULT hr = cmd.CreateInstance( __uuidof(ADODB::Command) );
// if ( FAILED( hr ) ) throw( _com_error( hr, NULL ) );

cmd->ActiveConnection = conn;

/*
Query: qiMissingRecord:

PARAMETERS P1 Long, P2 DateTime;
INSERT INTO T1 ( f1, f2 ) VALUES (P1, P2);
*/

// Create insert statement and setup params.
#ifdef USE_CMDPROC
cmd->CommandText = L"qiMissingRecord";
cmd->CommandType = ADODB::adCmdStoredProc;
#else
#ifdef USE_PARAMS
cmd->CommandText = L"INSERT INTO T1 ( f1, f2 ) VALUES (?, ?)";
#else
cmd->CommandText = L"INSERT INTO T1 ( f1, f2 ) VALUES (1, 2)";
#endif
cmd->CommandType = ADODB::adCmdText;
#endif

#ifdef USE_PARAMS
v1 = 1L;
v2 = lCounter++;
cmd->Parameters->Append(cmd->CreateParameter(
L"P1",ADODB::adInteger,ADODB::adParamInput,-1, v1));
cmd->Parameters->Append(cmd->CreateParameter(
L"P2",ADODB::adInteger,ADODB::adParamInput,-1, v2));
v1.Clear();
v2.Clear();
#endif

// Execute statement.
cmd->Execute(NULL,NULL,ADODB::adExecuteNoRecords);

// Cleanup
cmd->ActiveConnection = NULL;
cmd = NULL;
}


.



Relevant Pages