I have a Informix database, and table, where is one BLOB field (type: BYTE) and some INTEGER type fields. Connections to this base is going trough ADO. Table content is selected/updated with SQL SELECT/INSERT/UPDATE respectively. All was allright, but I get errors, if BLOB size exceeds 640 Kb - BLOB content get corrupted on write. I tried use AppendChunk/GetChunk, but recordset updates was unsuccesful. On rs.Update() I has error -611 (Scroll cursor can't select Blob columns) - if recordset has result of SQL SELECT query or -201 (Syntax error or access violation) - if this was be table recordset. Blob save/load functions is followed:
Connection string:
Provider=Ifxoledbc.2;User ID=informix;Password=informix;Persist Security Info=True;Data Source=mybase@myhost
// Save blob to database.
BOOL CADOBlob:BSaveBlob(const long lRecID, const BYTE *pBlob, const DWORD dwSize, BOOL bChunk)
{
HRESULT hr = S_OK;
_RecordsetPtr pRs = NULL;
CString strSQL;
_bstr_t bstrSQL;
_variant_t vBlob;
_variant_t vSize;
LPSAFEARRAY psa;
BYTE *lpArrayData;
BOOL bResult = TRUE;
strSQL.Format("select * from blobstore where id = %u;", lRecID);
bstrSQL = strSQL.AllocSysString();
vSize.vt = VT_I4;
vSize.lVal = dwSize;
try
{
// If record with given ID isn't exist and new record with this ID
// adding also failed, exit with FALSE.
if (!IsRecordExist(lRecID))
if (!AddNewRecord(lRecID))
return FALSE;
// Add blob to record.
pRs.CreateInstance(__uuidof(Recordset));
pRs->CursorLocation = adUseClient;
pRs->Open(bstrSQL, _variant_t((IDispatch *)m_pConnection, TRUE), adOpenKeyset, adLockOptimistic, adCmdText);
//pRs->Open("blobstore", _variant_t((IDispatch *)m_pConnection, TRUE), adOpenKeyset, adLockOptimistic, adCmdTable);
pRs->GetFields()->GetItem("size"->PutValue(vSize);
if(bChunk)
{
_variant_t vChunk;
DWORD dwOffset = 0;
DWORD dwLast;
psa = SafeArrayCreateVector(VT_UI1, 0, m_dwChunkSize);
if (!psa)
return E_OUTOFMEMORY;
while(dwOffset < dwSize)
{
// If blob tail is smaller than chunk size, redefine array to smaller size.
dwLast = dwSize - dwOffset;
if(dwLast < m_dwChunkSize)
{
SAFEARRAYBOUND *aDims = new SAFEARRAYBOUND[1];
aDims->cElements = dwLast;
aDims->lLbound = 0;
if (hr = SafeArrayRedim(psa, aDims)) throw hr;
}
SafeArrayAccessData(psa, (LPVOID*)&lpArrayData);
memcpy(lpArrayData, pBlob + dwOffset, psa->rgsabound[0].cElements);
SafeArrayUnaccessData(psa);
vChunk.vt = VT_ARRAY | VT_UI1;
vChunk.parray = psa;
pRs->GetFields()->GetItem("blob"->AppendChunk(vChunk);
dwOffset = dwOffset + m_dwChunkSize;
}
}
else
{
_variant_t vBlob;
psa = SafeArrayCreateVector(VT_UI1, 0, dwSize);
if (!psa)
return E_OUTOFMEMORY;
SafeArrayAccessData(psa, (LPVOID*)&lpArrayData);
memcpy(lpArrayData, pBlob, dwSize);
SafeArrayUnaccessData(psa);
vBlob.vt = VT_ARRAY | VT_UI1;
vBlob.parray = psa;
pRs->GetFields()->GetItem("blob"->PutValue(vBlob);
}
pRs->Update();
pRs->Close();
}
catch(const _com_error& e)
{
SendErrorMessage(e);
bResult = FALSE;
}
catch(...)
{
bResult = FALSE;
}
return bResult;
}
// Load blob from database.
BOOL CADOBlob:BLoadBlob(const long lRecID, BYTE **pBlob, DWORD *dwSize, BOOL bChunk)
{
HRESULT hr = S_OK;
_RecordsetPtr pRs = NULL;
CString strSQL;
_bstr_t bstrSQL;
BOOL bResult = TRUE;
strSQL.Format("select * from blobstore where id = %u;", lRecID);
bstrSQL = strSQL.AllocSysString();
try
{
if(IsRecordExist(lRecID))
{
pRs.CreateInstance(__uuidof(Recordset));
pRs->CursorLocation = adUseClient;
pRs->Open(bstrSQL, _variant_t((IDispatch *)m_pConnection, TRUE), adOpenKeyset, adLockPessimistic, adCmdText);
_variant_t vSize = pRs->GetFields()->GetItem("size"->GetValue();
// If size field is not Null and blob field contain something, load blob.
if((vSize.vt != VT_NULL) && (pRs->GetFields()->GetItem("blob"->ActualSize > 0))
{
*dwSize = vSize.lVal;
*pBlob = new BYTE[*dwSize];
// Chunk ot not chunk? That is the question
if(bChunk)
{
_variant_t vChunk;
DWORD dwOffset = 0;
DWORD dwLast;
long lChunkSize = (long)m_dwChunkSize;
while(dwOffset < *dwSize)
{
dwLast = *dwSize - dwOffset;
// If blob tail is smaller than chunk size, redefine smaller chunk size.
if(dwLast < m_dwChunkSize)
lChunkSize = dwLast;
// Load chunk and at to memory buffer.
vChunk = pRs->GetFields()->GetItem("blob"->GetChunk(lChunkSize);
memcpy(*pBlob + dwOffset, vChunk.parray->pvData, lChunkSize);
dwOffset = dwOffset + m_dwChunkSize;
}
}
else
{
_variant_t vBlob = pRs->GetFields()->GetItem("blob"->GetValue();
memcpy(*pBlob, vBlob.parray->pvData, *dwSize);
}
}
else
bResult = FALSE;
pRs->Close();
}
else
{
CString strMessage;
strMessage.Format("Record %u is not exist!", lRecID);
SendMessage(strMessage);
bResult = FALSE;
}
}
catch(const _com_error& e)
{
SendErrorMessage(e);
bResult = FALSE;
}
catch(...)
{
bResult = FALSE;
}
return bResult;
}
But on Access 2000 database those code is working without problems. What is wrong?
Informix server version - 7.31C4, Informix OLEDB driver version - 3.80
Connection string:
Provider=Ifxoledbc.2;User ID=informix;Password=informix;Persist Security Info=True;Data Source=mybase@myhost
// Save blob to database.
BOOL CADOBlob:BSaveBlob(const long lRecID, const BYTE *pBlob, const DWORD dwSize, BOOL bChunk)
{
HRESULT hr = S_OK;
_RecordsetPtr pRs = NULL;
CString strSQL;
_bstr_t bstrSQL;
_variant_t vBlob;
_variant_t vSize;
LPSAFEARRAY psa;
BYTE *lpArrayData;
BOOL bResult = TRUE;
strSQL.Format("select * from blobstore where id = %u;", lRecID);
bstrSQL = strSQL.AllocSysString();
vSize.vt = VT_I4;
vSize.lVal = dwSize;
try
{
// If record with given ID isn't exist and new record with this ID
// adding also failed, exit with FALSE.
if (!IsRecordExist(lRecID))
if (!AddNewRecord(lRecID))
return FALSE;
// Add blob to record.
pRs.CreateInstance(__uuidof(Recordset));
pRs->CursorLocation = adUseClient;
pRs->Open(bstrSQL, _variant_t((IDispatch *)m_pConnection, TRUE), adOpenKeyset, adLockOptimistic, adCmdText);
//pRs->Open("blobstore", _variant_t((IDispatch *)m_pConnection, TRUE), adOpenKeyset, adLockOptimistic, adCmdTable);
pRs->GetFields()->GetItem("size"->PutValue(vSize);
if(bChunk)
{
_variant_t vChunk;
DWORD dwOffset = 0;
DWORD dwLast;
psa = SafeArrayCreateVector(VT_UI1, 0, m_dwChunkSize);
if (!psa)
return E_OUTOFMEMORY;
while(dwOffset < dwSize)
{
// If blob tail is smaller than chunk size, redefine array to smaller size.
dwLast = dwSize - dwOffset;
if(dwLast < m_dwChunkSize)
{
SAFEARRAYBOUND *aDims = new SAFEARRAYBOUND[1];
aDims->cElements = dwLast;
aDims->lLbound = 0;
if (hr = SafeArrayRedim(psa, aDims)) throw hr;
}
SafeArrayAccessData(psa, (LPVOID*)&lpArrayData);
memcpy(lpArrayData, pBlob + dwOffset, psa->rgsabound[0].cElements);
SafeArrayUnaccessData(psa);
vChunk.vt = VT_ARRAY | VT_UI1;
vChunk.parray = psa;
pRs->GetFields()->GetItem("blob"->AppendChunk(vChunk);
dwOffset = dwOffset + m_dwChunkSize;
}
}
else
{
_variant_t vBlob;
psa = SafeArrayCreateVector(VT_UI1, 0, dwSize);
if (!psa)
return E_OUTOFMEMORY;
SafeArrayAccessData(psa, (LPVOID*)&lpArrayData);
memcpy(lpArrayData, pBlob, dwSize);
SafeArrayUnaccessData(psa);
vBlob.vt = VT_ARRAY | VT_UI1;
vBlob.parray = psa;
pRs->GetFields()->GetItem("blob"->PutValue(vBlob);
}
pRs->Update();
pRs->Close();
}
catch(const _com_error& e)
{
SendErrorMessage(e);
bResult = FALSE;
}
catch(...)
{
bResult = FALSE;
}
return bResult;
}
// Load blob from database.
BOOL CADOBlob:BLoadBlob(const long lRecID, BYTE **pBlob, DWORD *dwSize, BOOL bChunk)
{
HRESULT hr = S_OK;
_RecordsetPtr pRs = NULL;
CString strSQL;
_bstr_t bstrSQL;
BOOL bResult = TRUE;
strSQL.Format("select * from blobstore where id = %u;", lRecID);
bstrSQL = strSQL.AllocSysString();
try
{
if(IsRecordExist(lRecID))
{
pRs.CreateInstance(__uuidof(Recordset));
pRs->CursorLocation = adUseClient;
pRs->Open(bstrSQL, _variant_t((IDispatch *)m_pConnection, TRUE), adOpenKeyset, adLockPessimistic, adCmdText);
_variant_t vSize = pRs->GetFields()->GetItem("size"->GetValue();
// If size field is not Null and blob field contain something, load blob.
if((vSize.vt != VT_NULL) && (pRs->GetFields()->GetItem("blob"->ActualSize > 0))
{
*dwSize = vSize.lVal;
*pBlob = new BYTE[*dwSize];
// Chunk ot not chunk? That is the question
if(bChunk)
{
_variant_t vChunk;
DWORD dwOffset = 0;
DWORD dwLast;
long lChunkSize = (long)m_dwChunkSize;
while(dwOffset < *dwSize)
{
dwLast = *dwSize - dwOffset;
// If blob tail is smaller than chunk size, redefine smaller chunk size.
if(dwLast < m_dwChunkSize)
lChunkSize = dwLast;
// Load chunk and at to memory buffer.
vChunk = pRs->GetFields()->GetItem("blob"->GetChunk(lChunkSize);
memcpy(*pBlob + dwOffset, vChunk.parray->pvData, lChunkSize);
dwOffset = dwOffset + m_dwChunkSize;
}
}
else
{
_variant_t vBlob = pRs->GetFields()->GetItem("blob"->GetValue();
memcpy(*pBlob, vBlob.parray->pvData, *dwSize);
}
}
else
bResult = FALSE;
pRs->Close();
}
else
{
CString strMessage;
strMessage.Format("Record %u is not exist!", lRecID);
SendMessage(strMessage);
bResult = FALSE;
}
}
catch(const _com_error& e)
{
SendErrorMessage(e);
bResult = FALSE;
}
catch(...)
{
bResult = FALSE;
}
return bResult;
}
But on Access 2000 database those code is working without problems. What is wrong?
Informix server version - 7.31C4, Informix OLEDB driver version - 3.80