На главную Наши проекты:
Журнал   ·   Discuz!ML   ·   Wiki   ·   DRKB   ·   Помощь проекту
ПРАВИЛА FAQ Помощь Участники Календарь Избранное RSS
msm.ru
! Правила раздела C/C++: Базы данных
Модераторы: B.V.
  
    > ADO & Informix database + Blob field
      Есть база данных на 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, всё происходит успешно. Что делать, не понятно :(((
      0 пользователей читают эту тему (0 гостей и 0 скрытых пользователей)
      0 пользователей:


      Рейтинг@Mail.ru
      [ Script execution time: 0,0158 ]   [ 16 queries used ]   [ Generated: 24.04.24, 06:13 GMT ]