Microsoft KB Archive/234797

= PRB: CLongBinary Data Doesn't Update with CRecordset::Open appendOnly Option =

Article ID: 234797

Article Last Modified on 12/2/2003

-

APPLIES TO


 * Microsoft Visual C++ 5.0 Enterprise Edition
 * Microsoft Visual C++ 6.0 Enterprise Edition
 * Microsoft Visual C++ 5.0 Professional Edition
 * Microsoft Visual C++ 6.0 Professional Edition
 * Microsoft Visual C++ 6.0 Standard Edition

-



This article was previously published under Q234797



SYMPTOMS
When you call CRecordset::Open with the appendOnly option, you can't update any data that is in CLongBinary member variables. The Update call does not cause any errors, but the data in that field is not written to the database.



CAUSE
The CLongBinary member variable is not being bound to the table's column in the RFX_LongBinary function. RFX_LongBinary only binds the column if the recordset is updateable [CanUpdate returns TRUE], but when opened with the appendOnly option, the recordset is only appendable and not updateable.

NOTE: If a driver does not support SQL_GD_BOUND for the SQL_GETDATA_EXTENSIONS value of SQLGetInfo, MFC will attempt to perform SQL updates rather than positioned updates using SQLSetPos, and therefore you will not see this problem. For example, if you are using a SQL Server datasource, you will not see a problem.



RESOLUTION
Use one of the following three workarounds:

 Don't use the appendOnly option.

 Use a CByteArray for your member variable instead of CLongBinary. In this case, use the RFX_Binary function for data transfer; this function doesn't conditionally bind the column.

  Create your own version of the RFX_LongBinary function that also binds the column when the recordset is appendable. In your DoFieldExchange function, call this new function instead of MFC's version. Just copy RFX_LongBinary from the MFC source file Dbrfx.cpp, then change the code below from the following: case CFieldExchange::BindFieldToColumn: // Don't bind if using update SQL, just do SQLGetData on Fixup. if (!pFX->m_prs->m_bUseUpdateSQL && pFX->m_prs->CanUpdate) to the following: case CFieldExchange::BindFieldToColumn: // Don't bind if using update SQL, just do SQLGetData on Fixup. if (!pFX->m_prs->m_bUseUpdateSQL && (pFX->m_prs->CanUpdate || pFX->m_prs->CanAppend)) 



Steps to Reproduce the Problem
 Use the AppWizard to create a new MFC application that contains a CRecordset-derived class that is based on a table that contains a long binary column (such as an OLE object field in Microsoft Access).  Use code similar to the following to open the recordset with the appendOnly option and add a new record to the table (this code can be used with the sample Northwind database): CMyRecordset rs; rs.Open(CRecordset::dynaset, NULL, CRecordset::appendOnly);

CFile myBitmap("c:\\temp\\myBitmap.bmp", CFile::modeRead); //Read from bitmap file into buffer. LONG nTotalBytes = myBitmap.GetLength;

//Allocate a buffer for the input and read from file. BYTE * inputBuf = new BYTE[nTotalBytes]; UINT nBytesRead = myBitmap.Read(inputBuf, nTotalBytes); rs.AddNew; rs.m_FirstName = "Cleo"; rs.m_LastName = "Haw";

//Copy the data into the CLongBinary member variable. LPVOID pVoid = NULL; DWORD bmpSize = nTotalBytes; rs.m_Photo.m_hData = ::GlobalAlloc(GMEM_MOVEABLE,bmpSize); pVoid = ::GlobalLock(rs.m_Photo.m_hData); ::memcpy(pVoid,inputBuf,bmpSize); ::GlobalUnlock(rs.m_Photo.m_hData); rs.m_Photo.m_dwDataLength =::GlobalSize(rs.m_Photo.m_hData);

rs.SetFieldNull(&rs.m_Photo,FALSE); rs.SetFieldDirty(&rs.m_Photo,TRUE);

rs.Update; delete [] inputBuf; ::GlobalFree(rs.m_Photo.m_hData); </li></ol>

RESULTS: You will see that the record has been added but the binary field is Null.

<div class="references_section">