Наши проекты:
Журнал · Discuz!ML · Wiki · DRKB · Помощь проекту |
||
ПРАВИЛА | FAQ | Помощь | Поиск | Участники | Календарь | Избранное | RSS |
[18.221.129.19] |
|
Сообщ.
#1
,
|
|
|
Есть база данных на Informix, а в ней таблица, в которой есть Blob поле (тип BYTE) и несколько полей типа INTEGER. К базе соединяюсь через ADO. Записи добавляется, обновляется и читается с SQL INSERT, UPDATE и SELECT сообственно. Но при записи Blob'ов более 640 Kb появился глюк - содержание оних при этом портится и те становится нечитаемыми (в оригинале - блок данных, сжат ZLib'ом). Подумал, что это из-за того, что данные такого размера нелзя передавать одним блоком и пробовал пользоватся AppendChunk/GetChunk. Содержание записей при этом прочиталось успешно, но при попытке добвавить/обновить запись на .Update() процес полетел с ошибкой "-611: Scroll cursor can't select Blob columns" - это, если содержание рекордсета возвращается как результат SQL запроса, или "-201: Syntax error or access violation" - эсли открыть таблицу напрямую. Запись и считивание Blob'ов выглядит так:
Connection string: Provider=Ifxoledbc.2;User ID=informix;Password=informix;Persist Security Info=True;Data Source=mybase@myhost // Save blob to database. BOOL CADOBlob::DBSaveBlob(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::DBLoadBlob(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; } Что интересно, при попытке проделать то же самое не таблице Access 2000, всё происходит успешно. Что делать, не понятно (( |