📄 icrrowsetimpl.h
字号:
/****************************************************************************** * $Id: ICRRowsetImpl.h,v 1.3 2002/08/28 20:07:45 warmerda Exp $ * * Project: OpenGIS Simple Features Reference Implementation * Purpose: RowsetInterface implementation specifically for columns rowset. * Author: Frank Warmerdam <warmerdam@pobox.com> * * This code is closely derived from the code in ATLDB.H for IRowsetImpl. * It basically modifies the CRowsetImpl to call GetRCDBStatus() on the * derived class from the GetDBStatus() method, allowing a field to be marked * as DBSTATUS_S_ISNULL. Also, there are some changes to handle null field * status properly. * ****************************************************************************** * Copyright (c) 2001, Frank Warmerdam * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. ****************************************************************************** * * $Log: ICRRowsetImpl.h,v $ * Revision 1.3 2002/08/28 20:07:45 warmerda * Get the pSrcData from m_rgRowData[] in GetDBStatus() * * Revision 1.2 2002/08/28 17:42:07 warmerda * changed to unix text format * * Revision 1.1 2002/08/09 21:36:39 warmerda * New * * Revision 1.3 2002/01/31 16:47:41 warmerda * fix up docs a bit * * Revision 1.2 2001/10/15 15:21:07 warmerda * pass raw data points to GetRCDBStatus * */#ifndef _ICRRowsetImpl_INCLUDED#define _ICRRowsetImpl_INCLUDED// ICRRowsetImpltemplate <class T, class RowsetInterface, class RowClass = CSimpleRow, class MapClass = CAtlMap < RowClass::KeyType, RowClass* > >class ATL_NO_VTABLE ICRRowsetImpl : public RowsetInterface{public: typedef RowClass _HRowClass; ICRRowsetImpl() { m_iRowset = 0; m_bCanScrollBack = false; m_bCanFetchBack = false; m_bRemoveDeleted = true; m_bIRowsetUpdate = false; m_bReset = true; m_bExternalFetch = false; } ~ICRRowsetImpl() { //for (int i = 0; i < m_rgRowHandles.GetCount(); i++) // delete (m_rgRowHandles.GetValueAt(i)); POSITION pos = m_rgRowHandles.GetStartPosition(); while( pos != NULL ) { MapClass::CPair *pPair = m_rgRowHandles.GetNext(pos); ATLASSERT( pPair != NULL ); delete pPair->m_value; } } HRESULT RefRows(DBCOUNTITEM cRows, const HROW rghRows[], DBREFCOUNT rgRefCounts[], DBROWSTATUS rgRowStatus[], BOOL bAdd) { ATLTRACE(atlTraceDBProvider, 2, _T("ICRRowsetImpl::AddRefRows\n")); if (cRows == 0) return S_OK; if (rghRows == NULL) return E_INVALIDARG; T::ObjectLock cab((T*)this); BOOL bSuccess1 = FALSE; BOOL bFailed1 = FALSE; DBROWSTATUS rs; DWORD dwRef; __if_exists(T::Fire_OnRowChange) { // Maintain an array of handles w/ zero ref counts for notification CAtlArray<HROW> arrZeroHandles; } for (ULONG iRow = 0; iRow < cRows; iRow++) { HROW hRowCur = rghRows[iRow]; RowClass* pRow; bool bFound = m_rgRowHandles.Lookup((RowClass::KeyType)hRowCur, pRow); if (!bFound || pRow == NULL) { ATLTRACE(atlTraceDBProvider, 0, _T("Could not find HANDLE %x in list\n")); rs = DBROWSTATUS_E_INVALID; dwRef = 0; bFailed1 = TRUE; } else { if (pRow->m_status != DBPENDINGSTATUS_UNCHANGED && pRow->m_status != DBPENDINGSTATUS_INVALIDROW && pRow->m_dwRef == 0 && !bAdd) { if (rgRefCounts) rgRefCounts[iRow] = 0; if (rgRowStatus != NULL) rgRowStatus[iRow] = DBROWSTATUS_E_INVALID; bFailed1 = TRUE; continue; } // Check if we're in immediate or deferred mode CComVariant varDeferred; bool bDeferred; T* pT = (T*)this; HRESULT hr = pT->GetPropValue(&DBPROPSET_ROWSET, DBPROP_IRowsetUpdate, &varDeferred); (FAILED(hr) || varDeferred.boolVal == ATL_VARIANT_FALSE) ? bDeferred = false : bDeferred = true; if (!bDeferred && bAdd && pRow->m_status == DBPENDINGSTATUS_DELETED) { bFailed1 = TRUE; if (rgRowStatus != NULL) rgRowStatus[iRow] = DBROWSTATUS_E_DELETED; continue; } if (bAdd) dwRef = pRow->AddRefRow(); else { dwRef = pRow->ReleaseRow(); if ((pRow->m_status != DBPENDINGSTATUS_UNCHANGED && pRow->m_status != 0 && pRow->m_status != DBPENDINGSTATUS_INVALIDROW) && bDeferred) { if (rgRefCounts) rgRefCounts[iRow] = dwRef; if (rgRowStatus != NULL) rgRowStatus[iRow] = DBROWSTATUS_S_PENDINGCHANGES; bSuccess1 = TRUE; continue; } if (dwRef == 0) { __if_exists(T::Fire_OnRowsetChange) { _ATLTRY { arrZeroHandles.Add(hRowCur); } _ATLCATCH( e ) { _ATLDELETEEXCEPTION( e ); return E_FAIL; } } // Now determine if the DBPROP_REMOVEDELETED property // is ATL_VARIANT_FALSE. If so, then do NOT remove the // row. hr = pT->GetPropValue(&DBPROPSET_ROWSET, DBPROP_REMOVEDELETED, &varDeferred); if (FAILED(hr) || varDeferred.boolVal != ATL_VARIANT_FALSE) { delete pRow; m_rgRowHandles.RemoveKey((RowClass::KeyType)hRowCur); } } } bSuccess1 = TRUE; rs = DBROWSTATUS_S_OK; } if (rgRefCounts) rgRefCounts[iRow] = dwRef; if (rgRowStatus != NULL) rgRowStatus[iRow] = rs; } __if_exists(T::Fire_OnRowsetChange) { if (!bAdd && arrZeroHandles.GetCount() > 0) { T* pT = (T*)this; pT->Fire_OnRowChange(pT, (ULONG_PTR)arrZeroHandles.GetCount(), arrZeroHandles.GetData(), DBREASON_ROW_RELEASE, DBEVENTPHASE_DIDEVENT, FALSE); } } if (!bSuccess1 && !bFailed1) { ATLTRACE(atlTraceDBProvider, 0, _T("ICRRowsetImpl::RefRows Unexpected state\n")); return E_FAIL; } HRESULT hr = S_OK; if (bSuccess1 && bFailed1) hr = DB_S_ERRORSOCCURRED; if (!bSuccess1 && bFailed1) hr = DB_E_ERRORSOCCURRED; return hr; } STDMETHOD(AddRefRows)(DBCOUNTITEM cRows, const HROW rghRows[], DBREFCOUNT rgRefCounts[], DBROWSTATUS rgRowStatus[]) { ATLTRACE(atlTraceDBProvider, 2, _T("ICRRowsetImpl::AddRefRows\n")); if (cRows == 0) return S_OK; return RefRows(cRows, rghRows, rgRefCounts, rgRowStatus, TRUE); } virtual DBSTATUS GetDBStatus(RowClass* pRow, ATLCOLUMNINFO *poColInfo) { T* pT = (T*) this; void *pSrcData; pSrcData = (void*)&(pT->m_rgRowData[pRow->m_iRowset]); return pT->GetRCDBStatus(pRow, poColInfo, pSrcData); } virtual HRESULT SetDBStatus(DBSTATUS*, RowClass* , ATLCOLUMNINFO*) { // The provider overrides this function to handle special processing // for DBSTATUS_S_ISNULL and DBSTATUS_S_DEFAULT. return S_OK; } OUT_OF_LINE HRESULT GetDataHelper(HACCESSOR hAccessor, ATLCOLUMNINFO*& rpInfo, void** ppBinding, void*& rpSrcData, DBORDINAL& rcCols, CComPtr<IDataConvert>& rspConvert, RowClass* pRow) { ATLASSERT(ppBinding != NULL); T* pT = (T*) this;// *ppBinding = (void*)pT->m_rgBindings.Lookup((INT_PTR)hAccessor); T::_BindingVector::CPair* pPair = pT->m_rgBindings.Lookup( hAccessor ); if (pPair == NULL || pPair->m_value == NULL) return DB_E_BADACCESSORHANDLE; *ppBinding = pPair->m_value; rpSrcData = (void*)&(pT->m_rgRowData[pRow->m_iRowset]); rpInfo = T::GetColumnInfo((T*)this, &rcCols); rspConvert = pT->m_spConvert; return S_OK; } STDMETHOD(GetData)(HROW hRow, HACCESSOR hAccessor, void *pDstData) { T* pT = (T*)this; RowClass* pRow; if (hRow == NULL ) return DB_E_BADROWHANDLE; if( !pT->m_rgRowHandles.Lookup((INT_PTR)hRow, pRow)) return DB_E_BADROWHANDLE; if (pRow == NULL) return DB_E_BADROWHANDLE; return TransferData<T, RowClass, MapClass> (pT, true, pDstData, pRow, &(pT->m_rgRowHandles), hAccessor); } HRESULT CreateRow(DBROWOFFSET lRowsOffset, DBCOUNTITEM& cRowsObtained, HROW* rgRows) { RowClass* pRow = NULL; ATLASSERT(lRowsOffset >= 0); RowClass::KeyType key = lRowsOffset+1; ATLASSERT(key > 0); bool bFound = m_rgRowHandles.Lookup(key,pRow); if (!bFound || pRow == NULL) { ATLTRY(pRow = new RowClass(lRowsOffset)) if (pRow == NULL) return E_OUTOFMEMORY; _ATLTRY { m_rgRowHandles.SetAt(key, pRow); } _ATLCATCH( e ) { _ATLDELETEEXCEPTION( e ); delete pRow; pRow = NULL; return E_OUTOFMEMORY; } } pRow->AddRefRow(); m_bReset = false; rgRows[cRowsObtained++] = (HROW)key; return S_OK; } HRESULT GetNextRowsSkipDeleted(HCHAPTER /*hReserved*/, DBROWOFFSET lRowsOffset, DBROWCOUNT cRows, DBCOUNTITEM *pcRowsObtained, HROW **prghRows) { ATLTRACE(atlTraceDBProvider, 2, _T("ICRRowsetImpl::GetNextRows\n")); T* pT = (T*) this; __if_exists(T::Fire_OnRowChange) { // Check to see if someone is in an event handler. If we do, then // we should return DB_E_NOTREENTRANT. if (!pT->IncrementMutex()) { // Note, we can't set this above this block because we may // inadvertantly reset somebody else's pcRowsObtained if (pcRowsObtained != NULL) *pcRowsObtained = 0; return DB_E_NOTREENTRANT; } else pT->DecrementMutex(); } if (pcRowsObtained != NULL) *pcRowsObtained = 0; if (prghRows == NULL || pcRowsObtained == NULL) return E_INVALIDARG; if (cRows == 0) return S_OK; HRESULT hr = S_OK; T::ObjectLock cab(pT); if (lRowsOffset < 0 && !m_bCanScrollBack) return DB_E_CANTSCROLLBACKWARDS; if (cRows < 0 && !m_bCanFetchBack) return DB_E_CANTFETCHBACKWARDS; DBROWOFFSET cRowsInSet = (DBROWOFFSET)pT->m_rgRowData.GetCount(); DBROWOFFSET iStepSize = cRows >= 0 ? 1 : -1; // If cRows == MINLONG_PTR, we can't use ABS on it. Therefore, we reset it // to a value just greater than cRowsInSet if (cRows == MINLONG_PTR && cRowsInSet != MINLONG_PTR) cRows = cRowsInSet + 2; // set the value to something we can deal with else cRows = AbsVal(cRows); // First, simulate the operation, skipping over any deleted rows, calculate the number of rows retrieved, // and return an error code if appropriate DBROWOFFSET nCurrentRow = m_iRowset; // Note, if m_bReset, m_iRowset must be 0 if ( m_bReset && (lRowsOffset < 0 || ( lRowsOffset == 0 && iStepSize < 0 ) ) ) nCurrentRow = cRowsInSet; // skip the rows according to the lRowsOffset value if( lRowsOffset > 0 ) { DBROWOFFSET nRowsToSkip = lRowsOffset; while( nRowsToSkip > 0 && nCurrentRow <= cRowsInSet ) { RowClass* pRow = NULL; RowClass::KeyType key = nCurrentRow + 1; bool bFound = m_rgRowHandles.Lookup(key,pRow); if( bFound && pRow != NULL ) { if( pRow->m_status == DBPENDINGSTATUS_DELETED ) { nCurrentRow++; continue; } } nCurrentRow++; nRowsToSkip--; } if( nCurrentRow > cRowsInSet ) return DB_S_ENDOFROWSET; } else if( lRowsOffset < 0 ) { DBROWOFFSET nRowsToSkip = lRowsOffset; if (nRowsToSkip == MINLONG_PTR && cRowsInSet != MINLONG_PTR) nRowsToSkip = cRowsInSet + 2; // set the value to something we can deal with else nRowsToSkip = -nRowsToSkip; while( nRowsToSkip > 0 && nCurrentRow > 0 ) { nCurrentRow--; RowClass* pRow = NULL; RowClass::KeyType key = nCurrentRow + 1; bool bFound = m_rgRowHandles.Lookup(key,pRow); if( bFound && pRow != NULL ) { if( pRow->m_status == DBPENDINGSTATUS_DELETED ) { continue; } } nRowsToSkip--; } if( nCurrentRow < 0 ) return DB_S_ENDOFROWSET; } DBROWOFFSET nFetchStartPosition = nCurrentRow; // now fetch the rows DBROWOFFSET cRowsToFetch = cRows; DBROWOFFSET cRowsFetched = 0; if( iStepSize == 1 ) { while( cRowsToFetch > 0 && nCurrentRow < cRowsInSet ) { RowClass* pRow = NULL; RowClass::KeyType key = nCurrentRow + 1; bool bFound = m_rgRowHandles.Lookup(key,pRow); if( bFound && pRow != NULL ) { if( pRow->m_status == DBPENDINGSTATUS_DELETED ) { nCurrentRow++; continue; } } // now we would fetch the row cRowsFetched++; cRowsToFetch--; nCurrentRow++; } } else { while( cRowsToFetch > 0 && nCurrentRow > 0 ) { nCurrentRow--; RowClass* pRow = NULL; RowClass::KeyType key = nCurrentRow + 1; bool bFound = m_rgRowHandles.Lookup(key,pRow); if( bFound && pRow != NULL ) { if( pRow->m_status == DBPENDINGSTATUS_DELETED ) { continue; } } // now we would fetch the row cRowsFetched++; cRowsToFetch--; } } // we could not fetch any rows if( cRowsFetched == 0 ) return DB_S_ENDOFROWSET; // Simulation completed... no problems detected... we can now perform the real fetching // Fire events for OKTODO and ABOUTTODO after all validation has taken // place but before any permanent changes to the rowset state take place __if_exists(T::Fire_OnRowsetChange) { // Only fire these events if we're not being called by a bookmark // operation (which is why m_bExternalFetch would be set to true) if(!m_bExternalFetch) { HRESULT hrNotify = pT->Fire_OnRowsetChange(pT, DBREASON_ROWSET_FETCHPOSITIONCHANGE, DBEVENTPHASE_OKTODO, FALSE);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -