Microsoft KB Archive/113815

{|
 * width="100%"|

FIX: Deleting CRecordset Object Before Closing It

 * }

Q113815

-

The information in this article applies to:


 * The Microsoft Foundation Classes (MFC), included with:
 * Microsoft Visual C++, versions 1.5, 1.51

-

SYMPTOMS
If a CDatabase object is allocated and then passed into a CRecordset constructor the user may notice a memory leak if the CRecordset is deleted before calling CRecordset::Close. Not only will memory leak, but the following ODBC error may eventually occur when using snapshots (or more specifically, when using the cursor library):

General Error: Unable to create file buffer

State:S1000

CAUSE
A bug in the CRecordset destructor prevents the ::SQLFreeStmt from getting called for the ODBC statement handle (HSTMT) used by the CRecordset object.

RESOLUTION
To work around the problem, make sure that CRecordset::Close is called before it is deleted. One way to handle this is to put a call to CRecordset::Close in the destructor of the CRecordset-derived class.

STATUS
Microsoft has confirmed this to be a bug in the products listed at the beginning of this article. This bug was corrected in MFC version 3.0, included with Visual C++, 32-bit Edition, version 2.0.

MORE INFORMATION
The CRecordset destructor has the following code:

   CRecordset::~CRecordset {       if (!m_bRecordsetDb) m_pDatabase = NULL;

ASSERT_VALID(this);

TRY {           Close; if (m_bRecordsetDb) {               delete m_pDatabase; m_pDatabase = NULL; }       }        ... The m_bRecordsetDb is a flag that the CRecordset class uses to tell whether the CRecordset created the CDatabase object or whether it was passed to the CRecordset in the constructor. If a program passes in the CDatabase pointer to the CRecordset, looking at the code you can see that m_pDatabase will be set to NULL. Unfortunately this causes a problem when Close is called later in the function. In CRecordset::Close the following lines determine whether the HSTMT allocated by the CRecordset needs to be freed:

  if (m_pDatabase != SQL_NULL_HDBC) {         AFX_SQL_SYNC(::SQLFreeStmt(m_hstmtUpdate, SQL_DROP)); } Since m_pDatabase has been set to NULL and the CDatabase object still exists, we run into a problem because SQL_NULL_HDBC is equal to NULL. Thus, the statement handle is never freed although the CRecordset goes away. This normally isn't too much of a problem because statement handles get freed when a connection goes away. However, if you are re-using a CDatabase for multiple CRecordset objects, many allocated HSTMTs will accumulate.

Additional query words: 1.50 2.50 2.51 odbc

Keywords : kb16bitonly kbDatabase kbMFC kbODBC kbVC

Issue type :

Technology : kbAudDeveloper kbMFC