DWORD CDecodeThread::ThreadProc() { HRESULT hr; DWORD cmd; BOOL bEOS = FALSE; BOOL bReinit = FALSE; SetThreadName(-1, "LAVVideo Decode Thread"); HANDLE hWaitEvents[2] = { GetRequestHandle(), m_evInput }; while(1) { if (!bEOS && !bReinit) { // Wait for either an input sample, or an request WaitForMultipleObjects(2, hWaitEvents, FALSE, INFINITE); } if (CheckRequest(&cmd)) { switch (cmd) { case CMD_CREATE_DECODER: { CAutoLock lock(&m_ThreadCritSec); hr = CreateDecoderInternal(m_ThreadCallContext.pmt, m_ThreadCallContext.codec); Reply(hr); m_ThreadCallContext.pmt = nullptr; } break; case CMD_CLOSE_DECODER: { ClearQueues(); SAFE_DELETE(m_pDecoder); Reply(S_OK); } break; case CMD_FLUSH: { ClearQueues(); m_pDecoder->Flush(); Reply(S_OK); } break; case CMD_EOS: { bEOS = TRUE; m_evEOSDone.Reset(); Reply(S_OK); } break; case CMD_EXIT: { Reply(S_OK); return 0; } break; case CMD_INIT_ALLOCATOR: { CAutoLock lock(&m_ThreadCritSec); hr = m_pDecoder->InitAllocator(m_ThreadCallContext.allocator); Reply(hr); m_ThreadCallContext.allocator = nullptr; } break; case CMD_POST_CONNECT: { CAutoLock lock(&m_ThreadCritSec); hr = PostConnectInternal(m_ThreadCallContext.pin); Reply(hr); m_ThreadCallContext.pin = nullptr; } break; case CMD_REINIT: { CMediaType &mt = m_pLAVVideo->GetInputMediaType(); CreateDecoderInternal(&mt, m_Codec); m_TempSample[1] = m_NextSample; m_NextSample = m_FailedSample; m_FailedSample = nullptr; bReinit = TRUE; m_evEOSDone.Reset(); Reply(S_OK); m_bDecoderNeedsReInit = FALSE; } break; default: ASSERT(0); } } if (m_bDecoderNeedsReInit) { m_evInput.Reset(); continue; } if (bReinit && !m_NextSample) { if (m_TempSample[0]) { m_NextSample = m_TempSample[0]; m_TempSample[0] = nullptr; } else if (m_TempSample[1]) { m_NextSample = m_TempSample[1]; m_TempSample[1] = nullptr; } else { bReinit = FALSE; m_evEOSDone.Set(); m_evSample.Set(); continue; } } IMediaSample *pSample = GetSample(); if (!pSample) { // Process the EOS now that the sample queue is empty if (bEOS) { bEOS = FALSE; m_pDecoder->EndOfStream(); m_evEOSDone.Set(); m_evSample.Set(); } continue; } DecodeInternal(pSample); // Release the sample SafeRelease(&pSample); // Indicates we're done decoding this sample m_evDecodeDone.Set(); // Set the Sample Event to unblock any waiting threads m_evSample.Set(); } return 0; }
STDMETHODIMP CCUBRIDRowset::DeleteRows(HCHAPTER hReserved, DBCOUNTITEM cRows, const HROW rghRows[], DBROWSTATUS rgRowStatus[]) { ATLTRACE(atlTraceDBProvider, 2, "CCUBRIDRowset::DeleteRows\n"); ClearError(); if(m_nStatus==1) return RaiseError(E_UNEXPECTED, 1, __uuidof(IRowsetChange), L"This object is in a zombie state"); CHECK_UPDATABILITY(DBPROPVAL_UP_DELETE); if(cRows==0) return S_OK; if(rghRows==NULL && cRows>=1) return RaiseError(E_INVALIDARG, 0, __uuidof(IRowsetChange)); // Determine if we're in immediate or deferred mode bool bDeferred = IsDeferred(this); int hConn = GetSessionPtr()->GetConnection(); UINT uCodepage = GetSessionPtr()->GetCodepage(); BOOL bSuccess = false; BOOL bFailed = false; for(DBCOUNTITEM i=0;i<cRows;i++) { HROW hRow = rghRows[i]; // Attempt to locate the row in our map CCUBRIDRowsetRow *pRow; { bool bFound = m_rgRowHandles.Lookup((ULONG)hRow, pRow); if(!bFound || pRow==NULL) { // invalid handle bFailed = true; if(rgRowStatus) rgRowStatus[i] = DBROWSTATUS_E_INVALID; continue; } } if(pRow->m_status==DBPENDINGSTATUS_DELETED) { // already deleted if(rgRowStatus) rgRowStatus[i] = DBROWSTATUS_E_DELETED; bFailed = true; continue; } ATLASSERT( pRow->m_iRowset==(ULONG)-1 || pRow->m_iRowset<m_rgRowData.GetCount() ); DBROWSTATUS rowStat = DBROWSTATUS_S_OK; // mark the row as deleted if(pRow->m_status==DBPENDINGSTATUS_INVALIDROW) { bFailed = true; // unsigned high bit signified neg. number if(pRow->m_dwRef & 0x80000000) rowStat = DBROWSTATUS_E_INVALID; else rowStat = DBROWSTATUS_E_DELETED; } else if(pRow->m_iRowset==(ULONG)-1 && pRow->m_status!=DBPENDINGSTATUS_NEW) { // 새로 삽입되었고 Storage로 전송됐다. bFailed = true; rowStat = DBROWSTATUS_E_NEWLYINSERTED; } else { bSuccess = true; rowStat = DBROWSTATUS_S_OK; if(pRow->m_status==DBPENDINGSTATUS_NEW) MakeRowInvalid(this, pRow); else pRow->m_status = DBPENDINGSTATUS_DELETED; } if(!bDeferred && pRow->m_status==DBPENDINGSTATUS_DELETED) { // 변화를 지금 적용 // CCUBRIDRowsetRow의 delete는 ReleaseRows에서 이루어진다. HRESULT hr = pRow->WriteData(hConn, uCodepage, GetRequestHandle(), m_strTableName); if(FAILED(hr)) return hr; MakeRowInvalid(this, pRow); } if(rgRowStatus) rgRowStatus[i] = rowStat; } if(!bDeferred) DoCommit(this); // commit if(bFailed) { if(bSuccess) return DB_S_ERRORSOCCURRED; else return RaiseError(DB_E_ERRORSOCCURRED, 0, __uuidof(IRowsetChange)); } else return S_OK; }
DWORD CBaseSplitterFilter::ThreadProc() { if (m_pSyncReader) { m_pSyncReader->SetBreakEvent(GetRequestHandle()); } if (!DemuxInit()) { for (;;) { DWORD cmd = GetRequest(); if (cmd == CMD_EXIT) { CAMThread::m_hThread = nullptr; } Reply(S_OK); if (cmd == CMD_EXIT) { return 0; } } } m_eEndFlush.Set(); m_fFlushing = false; for (DWORD cmd = DWORD_ERROR; ; cmd = GetRequest()) { if (cmd == CMD_EXIT) { m_hThread = nullptr; Reply(S_OK); return 0; } SetThreadPriority(m_hThread, m_priority = THREAD_PRIORITY_NORMAL); m_rtStart = m_rtNewStart; m_rtStop = m_rtNewStop; DemuxSeek(m_rtStart); if (cmd != DWORD_ERROR) { Reply(S_OK); } m_eEndFlush.Wait(); m_pActivePins.RemoveAll(); POSITION pos = m_pOutputs.GetHeadPosition(); while (pos && !m_fFlushing) { CBaseSplitterOutputPin* pPin = m_pOutputs.GetNext(pos); if (pPin->IsConnected() && pPin->IsActive()) { m_pActivePins.AddTail(pPin); pPin->DeliverNewSegment(m_rtStart, m_rtStop, m_dRate); } } do { m_bDiscontinuitySent.RemoveAll(); } while (!DemuxLoop()); pos = m_pActivePins.GetHeadPosition(); while (pos && !CheckRequest(&cmd)) { m_pActivePins.GetNext(pos)->QueueEndOfStream(); } } ASSERT(0); // we should only exit via CMD_EXIT m_hThread = nullptr; return 0; }
STDMETHODIMP CCUBRIDRowset::Update(HCHAPTER hReserved, DBCOUNTITEM cRows, const HROW rghRows[], DBCOUNTITEM *pcRows, HROW **prgRows, DBROWSTATUS **prgRowStatus) { ATLTRACE(atlTraceDBProvider, 2, "CCUBRIDRowset::Update\n"); ClearError(); if(m_nStatus==1) return RaiseError(E_UNEXPECTED, 1, __uuidof(IRowsetUpdate), L"This object is in a zombie state"); CHECK_RESTART(__uuidof(IRowsetUpdate)); DBCOUNTITEM ulRows = 0; // update할 row 수 bool bNotIgnore = true; // prgRows, prgRowStatus를 무시할지 여부를 나타냄 // the following lines are used to fix the two _alloca calls below. Those calls are risky // because we may be allocating huge amounts of data. So instead I'll allocate that data on heap. // But if you use _alloca you don't have to worry about cleaning this memory. So we will use these // temporary variables to allocate memory on heap. As soon as we exit the function, the memory will // be cleaned up, just as if we were using alloca. So now, instead of calling alloca, I'll alloc // memory on heap using the two smnart pointers below, and then assing it to the actual pointers. CHeapPtr<HROW> spTempRows; CHeapPtr<DBROWSTATUS> spTempRowStatus; if(cRows || pcRows) { if(prgRows) *prgRows = NULL; if(prgRowStatus) *prgRowStatus = NULL; } else { bNotIgnore = false; // Don't do status or row arrays } // Check to see how many changes we'll undo if(pcRows) { *pcRows = NULL; if(prgRows==NULL) return E_INVALIDARG; } if(cRows) { if(rghRows==NULL) return E_INVALIDARG; ulRows = cRows; } else ulRows = (DBCOUNTITEM)m_rgRowHandles.GetCount(); int hConn = GetSessionPtr()->GetConnection(); UINT uCodepage = GetSessionPtr()->GetCodepage(); // NULL out pointers { if(prgRows && ulRows && bNotIgnore) { // Make a temporary buffer as we may not fill up everything // in the case where cRows == 0 if(cRows) *prgRows = (HROW*)CoTaskMemAlloc(ulRows * sizeof(HROW)); else { spTempRows.Allocate(ulRows); *prgRows = spTempRows; } if (*prgRows==NULL) return E_OUTOFMEMORY; } if(prgRowStatus && ulRows && bNotIgnore) { if(cRows) *prgRowStatus = (DBROWSTATUS*)CoTaskMemAlloc(ulRows * sizeof(DBROWSTATUS)); else { spTempRowStatus.Allocate(ulRows); *prgRowStatus = spTempRowStatus; } if(*prgRowStatus==NULL) { if(cRows) CoTaskMemFree(*prgRows); *prgRows = NULL; return E_OUTOFMEMORY; } } } bool bSucceeded = false; bool bFailed = false; ULONG ulCount = 0; // update된 row 수 POSITION pos = m_rgRowHandles.GetStartPosition(); for (ULONG ulRow = 0; ulRow < ulRows; ulRow++) { ULONG ulCurrentRow = ulCount; bool bDupRow = false; // 중복된 row ULONG ulAlreadyProcessed = 0; // 중복된 row의 handle의 위치 HROW hRowUpdate = NULL; // 현재 update할 row의 handle { if(cRows) { // row handle이 주어졌음 hRowUpdate = rghRows[ulRow]; for (ULONG ulCheckDup = 0; ulCheckDup < ulRow; ulCheckDup++) { if (hRowUpdate==rghRows[ulCheckDup] || IsSameRow(hRowUpdate, rghRows[ulCheckDup]) == S_OK) { ulAlreadyProcessed = ulCheckDup; bDupRow = true; break; } } } else { // 모든 row에 대해 update //ATLASSERT(ulRow < (ULONG)m_rgRowHandles.GetCount()); // delete된 row가 있으면 성립하지 않는다. ATLASSERT( pos != NULL ); MapClass::CPair* pPair = m_rgRowHandles.GetNext(pos); ATLASSERT( pPair != NULL ); hRowUpdate = pPair->m_key; } } if(prgRows && bNotIgnore) (*prgRows)[ulCurrentRow] = hRowUpdate; if(bDupRow) { // We've already set the row before, just copy status and // continue processing if(prgRowStatus && bNotIgnore) (*prgRowStatus)[ulCurrentRow] = (*prgRowStatus)[ulAlreadyProcessed]; ulCount++; continue; } // Fetch the RowClass and determine if it is valid CCUBRIDRowsetRow *pRow; { bool bFound = m_rgRowHandles.Lookup((ULONG)hRowUpdate, pRow); if (!bFound || pRow == NULL) { if (prgRowStatus && bNotIgnore) (*prgRowStatus)[ulCurrentRow] = DBROWSTATUS_E_INVALID; bFailed = true; ulCount++; continue; } } // If cRows is zero we'll go through all rows fetched. We // shouldn't increment the attempted count for rows that are // not changed if (cRows != 0 || (pRow != NULL && pRow->m_status != 0 && pRow->m_status != DBPENDINGSTATUS_UNCHANGED && pRow->m_status != DBPENDINGSTATUS_INVALIDROW)) ulCount++; else continue; if(cRows==0) pRow->AddRefRow(); switch (pRow->m_status) { case DBPENDINGSTATUS_INVALIDROW: // Row is bad or deleted { if(prgRowStatus && bNotIgnore) (*prgRowStatus)[ulCurrentRow] = DBROWSTATUS_E_DELETED; bFailed = true; } break; case DBPENDINGSTATUS_UNCHANGED: case 0: { // If the row's status is not changed, then just put S_OK // and continue. The spec says we should not transmit the // request to the data source (as nothing would change). if(prgRowStatus && bNotIgnore) (*prgRowStatus)[ulCurrentRow] = DBROWSTATUS_S_OK; bSucceeded = true; } break; default: { DBORDINAL cCols; ATLCOLUMNINFO *pColInfo = GetColumnInfo(this, &cCols); HRESULT hr = pRow->WriteData(hConn, uCodepage, GetRequestHandle(), m_strTableName); if(FAILED(hr)) { DBROWSTATUS stat = DBROWSTATUS_E_FAIL; if(hr==DB_E_INTEGRITYVIOLATION) stat = DBROWSTATUS_E_INTEGRITYVIOLATION; if(prgRowStatus && bNotIgnore) (*prgRowStatus)[ulCurrentRow] = stat; bFailed = true; } else { //// m_iRowset을 적당히 조정한다. //if(pRow->m_status==DBPENDINGSTATUS_NEW) //{ // // NEW인 row는 항상 rowset의 뒤에 몰려있다. // // 그 row 중 가장 작은 m_iRowset이 update 된 row의 m_iRowset이 되면 된다. // CCUBRIDRowsetRow::KeyType key = pRow->m_iRowset; // POSITION pos = m_rgRowHandles.GetStartPosition(); // while(pos) // { // CCUBRIDRowset::MapClass::CPair *pPair = m_rgRowHandles.GetNext(pos); // ATLASSERT(pPair); // CCUBRIDRowsetRow *pCheckRow = pPair->m_value; // if( pCheckRow && pCheckRow->m_iRowset < key ) // { // if(pCheckRow->m_iRowset<pRow->m_iRowset) // pRow->m_iRowset = pCheckRow->m_iRowset; // pCheckRow->m_iRowset++; // } // } // // TODO: 북마크 업데이트가 필요한데 어떻게 해야 할지 모르겠다. // // 새로 추가된 Row의 OID를 읽어들인다. // pRow->ReadData(GetRequestHandle(), true); //} if(pRow->m_status==DBPENDINGSTATUS_DELETED) MakeRowInvalid(this, pRow); else pRow->m_status = DBPENDINGSTATUS_UNCHANGED; if(prgRowStatus && bNotIgnore) (*prgRowStatus)[ulCurrentRow] = DBROWSTATUS_S_OK; bSucceeded = true; // Check if we need to release the row because it's ref was 0 // See the IRowset::ReleaseRows section in the spec for more // information if (pRow->m_dwRef == 0) { pRow->AddRefRow(); // Artifically bump this to remove it if( FAILED( RefRows(1, &hRowUpdate, NULL, NULL, false) ) ) return E_FAIL; } } } break; } } // Set the output for rows undone. if(pcRows) *pcRows = ulCount; if(ulCount==0) { if(prgRows) { CoTaskMemFree(*prgRows); *prgRows = NULL; } if(prgRowStatus) { CoTaskMemFree(*prgRowStatus); *prgRowStatus = NULL; } } else if(cRows==0) { // In the case where cRows == 0, we need to allocate the final // array of data. if(prgRows && bNotIgnore) { HROW *prgRowsTemp = (HROW *)CoTaskMemAlloc(ulCount*sizeof(HROW)); if(prgRowsTemp==NULL) return E_OUTOFMEMORY; memcpy(prgRowsTemp, *prgRows, ulCount*sizeof(HROW)); *prgRows = prgRowsTemp; } if(prgRowStatus && bNotIgnore) { DBROWSTATUS *prgRowStatusTemp = (DBROWSTATUS *)CoTaskMemAlloc(ulCount*sizeof(DBROWSTATUS)); if(prgRowStatusTemp==NULL) { CoTaskMemFree(*prgRows); *prgRows = NULL; return E_OUTOFMEMORY; } memcpy(prgRowStatusTemp, *prgRowStatus, ulCount*sizeof(DBROWSTATUS)); *prgRowStatus = prgRowStatusTemp; } } DoCommit(this); // commit // Send the return value if(!bFailed) return S_OK; else { return bSucceeded ? DB_S_ERRORSOCCURRED : DB_E_ERRORSOCCURRED; } }
STDMETHODIMP CCUBRIDRowset::Undo(HCHAPTER hReserved, DBCOUNTITEM cRows, const HROW rghRows[], DBCOUNTITEM *pcRowsUndone, HROW **prgRowsUndone, DBROWSTATUS **prgRowStatus) { ATLTRACE(atlTraceDBProvider, 2, "CCUBRIDRowset::Undo\n"); ClearError(); if(m_nStatus==1) return RaiseError(E_UNEXPECTED, 1, __uuidof(IRowsetUpdate), L"This object is in a zombie state"); CHECK_RESTART(__uuidof(IRowsetUpdate)); DBCOUNTITEM ulRows = 0; // undo할 row 수 bool bNotIgnore = true; // prgRowsUndone, prgRowStatus를 무시할지 여부를 나타냄 // the following lines are used to fix the two _alloca calls below. Those calls are risky // because we may be allocating huge amounts of data. So instead I'll allocate that data on heap. // But if you use _alloca you don't have to worry about cleaning this memory. So we will use these // temporary variables to allocate memory on heap. As soon as we exit the function, the memory will // be cleaned up, just as if we were using alloca. So now, instead of calling alloca, I'll alloc // memory on heap using the two smnart pointers below, and then assing it to the actual pointers. CHeapPtr<HROW> spTempRowsUndone; CHeapPtr<DBROWSTATUS> spTempRowStatus; if(cRows || pcRowsUndone) { if(prgRowsUndone) *prgRowsUndone = NULL; if(prgRowStatus) *prgRowStatus = NULL; } else { bNotIgnore = false; // Don't do status or row arrays } // Check to see how many changes we'll undo if(pcRowsUndone) { *pcRowsUndone = NULL; if(prgRowsUndone==NULL) return E_INVALIDARG; } if(cRows) { if(rghRows==NULL) return E_INVALIDARG; ulRows = cRows; } else ulRows = (DBCOUNTITEM)m_rgRowHandles.GetCount(); // NULL out pointers { if(prgRowsUndone && ulRows && bNotIgnore) { // Make a temporary buffer as we may not fill up everything // in the case where cRows == 0 if(cRows) *prgRowsUndone = (HROW*)CoTaskMemAlloc(ulRows * sizeof(HROW)); else { spTempRowsUndone.Allocate(ulRows); *prgRowsUndone = spTempRowsUndone; } if (*prgRowsUndone==NULL) return E_OUTOFMEMORY; } if(prgRowStatus && ulRows && bNotIgnore) { if(cRows) *prgRowStatus = (DBROWSTATUS*)CoTaskMemAlloc(ulRows * sizeof(DBROWSTATUS)); else { spTempRowStatus.Allocate(ulRows); *prgRowStatus = spTempRowStatus; } if(*prgRowStatus==NULL) { if(cRows) CoTaskMemFree(*prgRowsUndone); *prgRowsUndone = NULL; return E_OUTOFMEMORY; } } } bool bSucceeded = false; bool bFailed = false; ULONG ulUndone = 0; // undo된 row 수 POSITION pos = m_rgRowHandles.GetStartPosition(); for (ULONG ulUndoRow = 0; ulUndoRow < ulRows; ulUndoRow++) { ULONG ulCurrentRow = ulUndone; HROW hRowUndo = NULL; // 현재 undo할 row의 handle { if(cRows) { // row handle이 주어졌음 hRowUndo = rghRows[ulUndoRow]; } else { // 모든 row에 대해 undo // ATLASSERT(ulUndoRow < (ULONG)m_rgRowHandles.GetCount()); // delete된 row가 있으면 성립하지 않는다. ATLASSERT( pos != NULL ); MapClass::CPair* pPair = m_rgRowHandles.GetNext(pos); ATLASSERT( pPair != NULL ); hRowUndo = pPair->m_key; } } if(prgRowsUndone && bNotIgnore) (*prgRowsUndone)[ulCurrentRow] = hRowUndo; // Fetch the RowClass and determine if it is valid CCUBRIDRowsetRow *pRow; { bool bFound = m_rgRowHandles.Lookup((ULONG)hRowUndo, pRow); if (!bFound || pRow == NULL) { if (prgRowStatus && bNotIgnore) (*prgRowStatus)[ulCurrentRow] = DBROWSTATUS_E_INVALID; bFailed = true; ulUndone++; continue; } } // If cRows is zero we'll go through all rows fetched. We shouldn't // increment the count for rows that haven't been modified. if (cRows != 0 || (pRow != NULL && pRow->m_status != 0 && pRow->m_status != DBPENDINGSTATUS_UNCHANGED && pRow->m_status != DBPENDINGSTATUS_INVALIDROW)) ulUndone++; else continue; if(cRows==0) pRow->AddRefRow(); switch (pRow->m_status) { case DBPENDINGSTATUS_INVALIDROW: // 메모리와 storage 모두 존재하지 않는 row { // provider templates에서는 DELETED인데 // INVALID가 더 맞지 않을까 싶기도 한다. if(prgRowStatus && bNotIgnore) (*prgRowStatus)[ulCurrentRow] = DBROWSTATUS_E_DELETED; bFailed = true; } break; case DBPENDINGSTATUS_NEW: // 메모리 상에만 존재하는 row { // If the row is newly inserted, go ahead and mark its // row as INVALID (according to the specification). if(prgRowStatus && bNotIgnore) (*prgRowStatus)[ulCurrentRow] = DBROWSTATUS_S_OK; MakeRowInvalid(this, pRow); bSucceeded = true; } break; case DBPENDINGSTATUS_CHANGED: case DBPENDINGSTATUS_DELETED: // storage의 데이터를 가져와야 하는 경우 // delete 된 경우 메모리에 데이터가 있지만, CHANGED->DELETED 인 경우도 있을 수 있다. { // read data back pRow->ReadData(GetRequestHandle()); pRow->m_status = DBPENDINGSTATUS_UNCHANGED; if(prgRowStatus && bNotIgnore) (*prgRowStatus)[ulCurrentRow] = DBROWSTATUS_S_OK; bSucceeded = true; } break; default: // 0, DBPENDINGSTATUS_UNCHANGED, // storage의 데이터를 가져올 필요가 없는 경우 { pRow->m_status = DBPENDINGSTATUS_UNCHANGED; if(prgRowStatus && bNotIgnore) (*prgRowStatus)[ulCurrentRow] = DBROWSTATUS_S_OK; bSucceeded = true; } break; } // Check if we need to release the row because it's ref was 0 // See the IRowset::ReleaseRows section in the spec for more // information if (pRow->m_dwRef == 0) { pRow->AddRefRow(); // Artifically bump this to remove it if( FAILED( RefRows(1, &hRowUndo, NULL, NULL, false) ) ) return E_FAIL; } } // Set the output for rows undone. if(pcRowsUndone) *pcRowsUndone = ulUndone; if(ulUndone==0) { if(prgRowsUndone) { CoTaskMemFree(*prgRowsUndone); *prgRowsUndone = NULL; } if(prgRowStatus) { CoTaskMemFree(*prgRowStatus); *prgRowStatus = NULL; } } else if(cRows==0) { // In the case where cRows == 0, we need to allocate the final // array of data. if(prgRowsUndone && bNotIgnore) { HROW *prgRowsTemp = (HROW *)CoTaskMemAlloc(ulUndone*sizeof(HROW)); if(prgRowsTemp==NULL) return E_OUTOFMEMORY; memcpy(prgRowsTemp, *prgRowsUndone, ulUndone*sizeof(HROW)); *prgRowsUndone = prgRowsTemp; } if(prgRowStatus && bNotIgnore) { DBROWSTATUS *prgRowStatusTemp = (DBROWSTATUS *)CoTaskMemAlloc(ulUndone*sizeof(DBROWSTATUS)); if(prgRowStatusTemp==NULL) { CoTaskMemFree(*prgRowsUndone); *prgRowsUndone = NULL; return E_OUTOFMEMORY; } memcpy(prgRowStatusTemp, *prgRowStatus, ulUndone*sizeof(DBROWSTATUS)); *prgRowStatus = prgRowStatusTemp; } } // Send the return value if(!bFailed) return S_OK; else { return bSucceeded ? DB_S_ERRORSOCCURRED : DB_E_ERRORSOCCURRED; } }
STDMETHODIMP CCUBRIDRowset::GetOriginalData(HROW hRow, HACCESSOR hAccessor, void *pData) { ATLTRACE(atlTraceDBProvider, 2, _T("CCUBRIDRowset::GetOriginalData\n")); ClearError(); if(m_nStatus==1) return RaiseError(E_UNEXPECTED, 1, __uuidof(IRowsetUpdate), L"This object is in a zombie state"); CHECK_RESTART(__uuidof(IRowsetUpdate)); // 바인딩 정보를 구함 ATLBINDINGS *pBinding; { bool bFound = m_rgBindings.Lookup((ULONG)hAccessor, pBinding); if(!bFound || pBinding==NULL) return DB_E_BADACCESSORHANDLE; if(!(pBinding->dwAccessorFlags & DBACCESSOR_ROWDATA)) return DB_E_BADACCESSORTYPE; // row accessor 가 아니다. if(pData==NULL && pBinding->cBindings!=0) return E_INVALIDARG; } // Attempt to locate the row in our map CCUBRIDRowsetRow *pRow; { bool bFound = m_rgRowHandles.Lookup((ULONG)hRow, pRow); if(!bFound || pRow==NULL) return DB_E_BADROWHANDLE; } // If the status is DBPENDINGSTATUS_INVALIDROW, the row has been // deleted and the change transmitted to the data source. In // this case, we can't get the original data so return // DB_E_DELETEDROW. if (pRow->m_status == DBPENDINGSTATUS_INVALIDROW) return DB_E_DELETEDROW; // Determine if we have a pending insert. In this case, the // spec says revert to default values, and if defaults, // are not available, then NULLs. if (pRow->m_status == DBPENDINGSTATUS_NEW) { for (ULONG lBind=0; lBind<pBinding->cBindings; lBind++) { DBBINDING* pBindCur = &(pBinding->pBindings[lBind]); // default value가 없으므로 NULL로 set if (pBindCur->dwPart & DBPART_VALUE) *((BYTE *)pData+pBindCur->obValue) = NULL; if (pBindCur->dwPart & DBPART_STATUS) *((DBSTATUS*)((BYTE*)(pData) + pBindCur->obStatus)) = DBSTATUS_S_ISNULL; } return S_OK; } // 새로 삽입된 Row if(pRow->m_iRowset==(ULONG)-1) { return pRow->WriteData(pBinding, pData, 0); } DBORDINAL cCols; ATLCOLUMNINFO *pInfo = GetColumnInfo(this, &cCols); DBROWCOUNT dwBookmark = pRow->m_iRowset+3;//Util::FindBookmark(m_rgBookmarks, (LONG)pRow->m_iRowset+1); // 임시 RowClass를 통해 storage에서 데이터를 읽어온 후, pData로 전송한다. CCUBRIDRowsetRow OrigRow(m_uCodepage, pRow->m_iRowset, cCols, pInfo, m_spConvert, m_Columns.m_defaultVal); OrigRow.ReadData(GetRequestHandle()); return OrigRow.WriteData(pBinding, pData, dwBookmark); }
STDMETHODIMP CCUBRIDRowset::InsertRow(HCHAPTER hReserved, HACCESSOR hAccessor, void *pData, HROW *phRow) { ATLTRACE(atlTraceDBProvider, 2, "CCUBRIDRowset::InsertRow\n"); if(phRow) *phRow = NULL; if(phRow) CHECK_CANHOLDROWS(__uuidof(IRowsetChange)); ClearError(); if(m_nStatus==1) return RaiseError(E_UNEXPECTED, 1, __uuidof(IRowsetChange), L"This object is in a zombie state"); CHECK_UPDATABILITY(DBPROPVAL_UP_INSERT); // Determine if we're in immediate or deferred mode bool bDeferred = IsDeferred(this); // 바인딩 정보를 구함 ATLBINDINGS *pBinding; { bool bFound = m_rgBindings.Lookup((ULONG)hAccessor, pBinding); if(!bFound || pBinding==NULL) return RaiseError(DB_E_BADACCESSORHANDLE, 0, __uuidof(IRowsetChange)); if(!(pBinding->dwAccessorFlags & DBACCESSOR_ROWDATA)) return RaiseError(DB_E_BADACCESSORTYPE, 0, __uuidof(IRowsetChange)); // row accessor 가 아니다. if(pData==NULL && pBinding->cBindings!=0) return RaiseError(E_INVALIDARG, 0, __uuidof(IRowsetChange)); } CCUBRIDRowsetRow *pRow; CCUBRIDRowsetRow::KeyType key; { // 새 row를 위한 Row class를 생성한다. DBORDINAL cCols; ATLCOLUMNINFO *pColInfo = GetColumnInfo(this, &cCols); ATLTRY(pRow = new CCUBRIDRowsetRow(m_uCodepage, -1, cCols, pColInfo, m_spConvert, m_Columns.m_defaultVal)); if(pRow==NULL) return RaiseError(E_OUTOFMEMORY, 0, __uuidof(IRowsetChange)); // row handle에 추가 key = (CCUBRIDRowsetRow::KeyType)m_rgRowData.GetCount(); if (key == 0) key++; while(m_rgRowHandles.Lookup(key)) key++; m_rgRowHandles.SetAt(key, pRow); // rowset에 데이터가 하나 늘었다. // m_rgRowData.SetCount(m_rgRowData.GetCount()+1); } HRESULT hrRead = pRow->ReadData(pBinding, pData, m_uCodepage); if(FAILED(hrRead)) { // m_rgRowData.SetCount(m_rgRowData.GetCount()-1); m_rgRowHandles.RemoveKey(key); delete pRow; return hrRead; } pRow->m_status = DBPENDINGSTATUS_NEW; if(phRow) { // handle을 반환할 때는 참조 카운트를 하나 증가시킨다. pRow->AddRefRow(); *phRow = (HROW)key; } // m_rgBookmarks.Add(pRow->m_iRowset+1); if(!bDeferred) { // 변화를 지금 적용 int hConn = GetSessionPtr()->GetConnection(); UINT uCodepage = GetSessionPtr()->GetCodepage(); HRESULT hr = pRow->WriteData(hConn, uCodepage, GetRequestHandle(), m_strTableName); if(FAILED(hr)) { pRow->ReleaseRow(); if (phRow != NULL) *phRow = NULL; return hr; } pRow->m_status = 0; // or UNCHANGED? if(pRow->m_dwRef==0) { m_rgRowHandles.RemoveKey(key); delete pRow; } DoCommit(this); // commit //// deferred update 모드였다가 immediate update 모드로 바뀌지는 않으므로 //// 다른 NEW 상태의 row는 없다. 즉 m_iRowset을 변경해야 할 row는 없다. //// 새로 추가된 Row의 OID를 읽어들인다. //pRow->ReadData(GetRequestHandle(), true); } return hrRead; }
STDMETHODIMP CCUBRIDRowset::SetData(HROW hRow, HACCESSOR hAccessor, void *pData) { ATLTRACE(atlTraceDBProvider, 2, "CCUBRIDRowset::SetData\n"); ClearError(); if(m_nStatus==1) return RaiseError(E_UNEXPECTED, 1, __uuidof(IRowsetChange), L"This object is in a zombie state"); // cci_cursor_update를 이용하면 질의를 재실행할 때까지 SetData를 실행할 수 없다. // SQL and cci_execute를 이용하면 가능하다. CHECK_RESTART(__uuidof(IRowsetChange)); CHECK_UPDATABILITY(DBPROPVAL_UP_CHANGE); // Determine if we're in immediate or deferred mode bool bDeferred = IsDeferred(this); // Attempt to locate the row in our map CCUBRIDRowsetRow *pRow; { bool bFound = m_rgRowHandles.Lookup((ULONG)hRow, pRow); if(!bFound || pRow==NULL) return RaiseError(DB_E_BADROWHANDLE, 0, __uuidof(IRowsetChange)); } ATLASSERT( pRow->m_iRowset==(ULONG)-1 || pRow->m_iRowset<m_rgRowData.GetCount() ); // 이미 지워진 row if(pRow->m_status==DBPENDINGSTATUS_DELETED || pRow->m_status==DBPENDINGSTATUS_INVALIDROW) return RaiseError(DB_E_DELETEDROW, 0, __uuidof(IRowsetChange)); // 새로 삽입되었고 Storage로 전송됐다. if(pRow->m_iRowset==(ULONG)-1 && pRow->m_status!=DBPENDINGSTATUS_NEW) return DB_E_NEWLYINSERTED; // 바인딩 정보를 구함 ATLBINDINGS *pBinding; { bool bFound = m_rgBindings.Lookup((ULONG)hAccessor, pBinding); if(!bFound || pBinding==NULL) return RaiseError(DB_E_BADACCESSORHANDLE, 0, __uuidof(IRowsetChange)); if(!(pBinding->dwAccessorFlags & DBACCESSOR_ROWDATA)) return RaiseError(DB_E_BADACCESSORTYPE, 0, __uuidof(IRowsetChange)); // row accessor 가 아니다. if(pData==NULL && pBinding->cBindings!=0) return RaiseError(E_INVALIDARG, 0, __uuidof(IRowsetChange)); } HRESULT hr = pRow->ReadData(pBinding, pData, m_uCodepage); if(FAILED(hr)) return hr; // 새로 삽입된 row는 변경이 있어도 그냥 새로 삽입된 것으로 표시 if(pRow->m_status!=DBPENDINGSTATUS_NEW) pRow->m_status = DBPENDINGSTATUS_CHANGED; if(!bDeferred) { // 변화를 지금 적용 int hConn = GetSessionPtr()->GetConnection(); UINT uCodepage = GetSessionPtr()->GetCodepage(); hr = pRow->WriteData(hConn, uCodepage, GetRequestHandle(), m_strTableName); if (hr == DB_E_INTEGRITYVIOLATION) return RaiseError(DB_E_INTEGRITYVIOLATION, 0, __uuidof(IRowsetChange)); if(FAILED(hr)) return RaiseError(DB_E_ERRORSOCCURRED, 0, __uuidof(IRowsetChange)); pRow->m_status = 0; // or UNCHANGED? DoCommit(this); // commit } return hr; // S_OK or DB_S_ERRORSOCCURRED }