📄 atldbcli.h
字号:
ULONG nRowsFetched;
CComPtr<IRowsetScroll> spRowsetScroll;
HRESULT hr = m_spRowset->QueryInterface(&spRowsetScroll);
if (FAILED(hr))
return hr;
ReleaseRows();
HROW* phRow = &m_hRow;
hr = spRowsetScroll->GetRowsAtRatio(NULL, NULL, nNumerator, nDenominator, (bForward) ? 1 : -1,
&nRowsFetched, &phRow);
// Note we're not using SUCCEEDED here, because we could get DB_S_ENDOFROWSET
if (hr == S_OK)
hr = GetData();
return hr;
}
// Implementation
static const IID& GetIID()
{
return IID_IRowset;
}
IRowset* GetInterface() const
{
return m_spRowset;
}
IRowset** GetInterfacePtr()
{
return &m_spRowset;
}
void SetupOptionalRowsetInterfaces()
{
// Cache IRowsetChange if available
if (m_spRowset != NULL)
m_spRowset->QueryInterface(&m_spRowsetChange);
}
HRESULT BindFinished() const { return S_OK; }
void SetAccessor(CAccessorBase* pAccessor)
{
m_pAccessor = pAccessor;
}
CComPtr<IRowset> m_spRowset;
CComPtr<IRowsetChange> m_spRowsetChange;
CAccessorBase* m_pAccessor;
HROW m_hRow;
};
///////////////////////////////////////////////////////////////////////////
// class CBulkRowset
class CBulkRowset : public CRowset
{
public:
CBulkRowset()
{
// Default the number of rows to bulk fetch to 10
m_nRows = 10;
m_hr = S_OK;
m_phRow = NULL;
}
CBulkRowset::~CBulkRowset()
{
Close();
delete [] m_phRow;
}
// Set the number of row handles that will be retrieved in each
// bulk row fetch. The default is 10 and this function must be called
// before Open if you wish to change it.
void SetRows(ULONG nRows)
{
// This function must be called before the memory is allocated
// during binding
ATLASSERT(m_phRow == NULL);
m_nRows = nRows;
}
// AddRef all the currently retrieved row handles
HRESULT AddRefRows()
{
ATLASSERT(m_spRowset != NULL);
return m_spRowset->AddRefRows(m_nCurrentRows, m_phRow, NULL, NULL);
}
// Release all the currently retrieved row handles
HRESULT ReleaseRows()
{
ATLASSERT(m_spRowset != NULL);
// We're going to Release the rows so reset the current row position
m_nCurrentRow = 0;
m_hRow = NULL;
return m_spRowset->ReleaseRows(m_nCurrentRows, m_phRow, NULL, NULL, NULL);
}
// Move to the first record
HRESULT MoveFirst()
{
ATLASSERT(m_spRowset != NULL);
ReleaseRows();
// Cause MoveNext to perform a new bulk fetch
m_nCurrentRow = m_nRows;
HRESULT hr = m_spRowset->RestartPosition(NULL);
if (FAILED(hr))
return hr;
// Get the data
return MoveNext();
}
// Move to the next record
HRESULT MoveNext()
{
ATLASSERT(m_spRowset != NULL);
ATLASSERT(m_phRow != NULL);
// Move to the next record in the buffer
m_nCurrentRow++;
// Have we reached the end of the buffer?
if (m_nCurrentRow >= m_nCurrentRows)
{
// If we've reached the end of the buffer and we had a non S_OK HRESULT from
// the last call to GetNextRows then return that HRESULT now.
if (m_hr != S_OK)
return m_hr;
// We've finished with these rows so we need some more
// First release any HROWs that we have
ReleaseRows();
m_hr = m_spRowset->GetNextRows(NULL, 0, m_nRows, &m_nCurrentRows, &m_phRow);
// If we have an error HRESULT or we haven't retrieved any rows then return
// the HRESULT now.
if (FAILED(m_hr) || m_nCurrentRows == 0)
return m_hr;
}
// Get the data for the current row
m_hRow = m_phRow[m_nCurrentRow];
return GetData();
}
// Move to the previous record
HRESULT MovePrev()
{
ATLASSERT(m_spRowset != NULL);
ATLASSERT(m_phRow != NULL);
// Check if we're at the start of the block
if (m_nCurrentRow == 0)
{
ReleaseRows();
// Go back the amount of rows in the block - 1 and fetch forward
m_hr = m_spRowset->GetNextRows(NULL, -(LONG)m_nRows-1, m_nRows, &m_nCurrentRows, &m_phRow);
// Set the current record to the end of the new block
m_nCurrentRow = m_nCurrentRows - 1;
// If we have an error HRESULT or we haven't retrieved any rows then return
// the HRESULT now.
if (FAILED(m_hr) || m_nCurrentRows == 0)
return m_hr;
}
else
{
// Move back a row in the block
m_nCurrentRow--;
}
// Get the data for the current row
m_hRow = m_phRow[m_nCurrentRow];
return GetData();
}
// Move to the last record
HRESULT MoveLast()
{
ReleaseRows();
return CRowset::MoveLast();
}
// Move to the passed bookmark
HRESULT MoveToBookmark(const CBookmarkBase& bookmark, LONG lSkip = 0)
{
ATLASSERT(m_spRowset != NULL);
CComPtr<IRowsetLocate> spLocate;
HRESULT hr = m_spRowset->QueryInterface(&spLocate);
if (FAILED(hr))
return hr;
ReleaseRows();
m_hr = spLocate->GetRowsAt(NULL, NULL, bookmark.GetSize(), bookmark.GetBuffer(),
lSkip, m_nRows, &m_nCurrentRows, &m_phRow);
if (m_hr != S_OK || m_nCurrentRows == 0)
return m_hr;
// Get the data
m_hRow = m_phRow[m_nCurrentRow];
return GetData();
}
// Move to a fractional position in the rowset
HRESULT MoveToRatio(ULONG nNumerator, ULONG nDenominator)
{
ATLASSERT(m_spRowset != NULL);
CComPtr<IRowsetScroll> spRowsetScroll;
HRESULT hr = m_spRowset->QueryInterface(&spRowsetScroll);
if (FAILED(hr))
return hr;
ReleaseRows();
m_hr = spRowsetScroll->GetRowsAtRatio(NULL, NULL, nNumerator, nDenominator, m_nRows, &m_nCurrentRows, &m_phRow);
if (m_hr != S_OK || m_nCurrentRows == 0)
return m_hr;
// Get the data
m_hRow = m_phRow[m_nCurrentRow];
return GetData();
}
// Insert the current record
HRESULT Insert(int nAccessor = 0, bool bGetHRow = false)
{
ReleaseRows();
return CRowset::Insert(nAccessor, bGetHRow);
}
// Implementation
HRESULT BindFinished()
{
// No rows in the buffer yet
m_nCurrentRows = 0;
// Cause MoveNext to automatically perform a new bulk fetch the first time
m_nCurrentRow = m_nRows;
m_phRow = NULL;
ATLTRY(m_phRow = new HROW[m_nRows]);
if (m_phRow == NULL)
return E_OUTOFMEMORY;
return S_OK;
}
HRESULT m_hr; // HRESULT to return from MoveNext at end of buffer
HROW* m_phRow; // Pointer to array of HROWs for each row in buffer
ULONG m_nRows; // Number of rows that will fit in the buffer
ULONG m_nCurrentRows; // Number of rows currently in the buffer
ULONG m_nCurrentRow;
};
///////////////////////////////////////////////////////////////////////////
// class CArrayRowset
//
// Allows you to access a rowset with an array syntax
template <class T, class TRowset = CRowset>
class CArrayRowset :
public CVirtualBuffer<T>,
public TRowset
{
public:
CArrayRowset(int nMax = 100000) : CVirtualBuffer<T>(nMax)
{
m_nRowsRead = 0;
}
T& operator[](int nRow)
{
ATLASSERT(nRow >= 0);
HRESULT hr = S_OK;
T* m_pCurrent = m_pBase + m_nRowsRead;
// Retrieve the row if we haven't retrieved it already
while ((ULONG)nRow >= m_nRowsRead)
{
m_pAccessor->SetBuffer((BYTE*)m_pCurrent);
__try
{
// Get the row
hr = MoveNext();
if (hr != S_OK)
break;
}
__except(Except(GetExceptionInformation()))
{
}
m_nRowsRead++;
m_pCurrent++;
}
if (hr != S_OK)
*((char*)0) = 0; // Force exception
return *(m_pBase + nRow);
}
HRESULT Snapshot()
{
ATLASSERT(m_nRowsRead == 0);
ATLASSERT(m_spRowset != NULL);
HRESULT hr = MoveFirst();
if (FAILED(hr))
return hr;
do
{
Write(*(T*)m_pAccessor->GetBuffer());
m_nRowsRead++;
hr = MoveNext();
} while (SUCCEEDED(hr) && hr != DB_S_ENDOFROWSET);
return (hr == DB_S_ENDOFROWSET) ? S_OK : hr;
}
// Implementation
ULONG m_nRowsRead;
};
// Used when you don't need any parameters or output columns
class CNoAccessor
{
public:
// We don't need any typedef's here as the default
// global typedef is not to have any parameters and
// output columns.
HRESULT BindColumns(IUnknown*) { return S_OK; }
HRESULT BindParameters(HACCESSOR*, ICommand*, void**) { return S_OK; }
void Close() { }
HRESULT ReleaseAccessors(IUnknown*) { return S_OK; }
};
// Used when a rowset will not be returned from the command
class CNoRowset
{
public:
HRESULT BindFinished() { return S_OK; }
void Close() { }
static const IID& GetIID() { return IID_NULL; }
IRowset* GetInterface() const { return NULL; }
IRowset** GetInterfacePtr() { return NULL; }
void SetAccessor(void*) { }
void SetupOptionalRowsetInterfaces() { }
};
///////////////////////////////////////////////////////////////////////////
// class CAccessor
// T is the class that contains the data that will be accessed.
template <class T>
class CAccessor :
public T,
public CAccessorBase
{
public:
// Implementation
// Free's any columns in the current record that need to be freed.
// E.g. Calls SysFreeString on any BSTR's and Release on any interfaces.
void FreeRecordMemory(IRowset* /* pRowset */)
{
ULONG nColumns;
ULONG i;
for (i = 0; i < GetNumAccessors(); i++)
{
// Passing in m_pBuffer tells the column entry maps to free the
// memory for the types if appropriate
_GetBindEntries(&nColumns, NULL, i, NULL, m_pBuffer);
}
}
HRESULT BindColumns(IUnknown* pUnk)
{
HRESULT hr;
ULONG nAccessors;
ULONG nSize;
nAccessors = _OutputColumnsClass::_GetNumAccessors();
SetBuffer((BYTE*)this);
nSize = sizeof(T);
hr = BindAccessors(nAccessors, nSize, pUnk);
return hr;
}
HRESULT BindAccessors(ULONG nAccessors, ULONG nSize, IUnknown* pUnk)
{
ATLASSERT(pUnk != NULL);
HRESULT hr;
CComPtr<IAccessor> spAccessor;
hr = pUnk->QueryInterface(&spAccessor);
if (SUCCEEDED(hr))
{
// Allocate the accessor memory if we haven't done so yet
if (m_pAccessorInfo == NULL)
{
hr = AllocateAccessorMemory(nAccessors);
if (FAILED(hr))
return hr;
}
for (ULONG i=0; i<nAccessors && SUCCEEDED(hr); i++)
hr = BindAccessor(spAccessor, i, nSize);
}
return hr;
}
HRESULT BindAccessor(IAccessor* pAccessor, ULONG nAccessor, ULONG nSize)
{
DBBINDING* pBindings = NULL;
ULONG nColumns;
bool bAuto;
HRESULT hr;
// First time just get the number of entries by passing in &nColumns
_OutputColumnsClass::_GetBindEntries(&nColumns, NULL, nAccessor, NULL);
// Now allocate the binding structures
ATLTRY(pBindings = new DBBINDING[nColumns]);
if (pBindings == NULL)
return E_OUTOFMEMORY;
// Now get the bind entries
hr = _OutputColumnsClass::_GetBindEntries(&nColumns, pBindings, nAccessor, &bAuto);
if (FAILED(hr))
return hr;
m_pAccessorInfo[nAccessor].bAutoAccessor = bAuto;
hr = BindEntries(pBindings, nColumns, &m_pAccessorInfo[nAccessor].hAccessor, nSize, pAccessor);
delete [] pBindings;
return hr;
}
HRESULT BindParameters(HACCESSOR* pHAccessor, ICommand* pCommand, void** ppParameterBuffer)
{
HRESULT hr = S_OK;
// In the static accessor case, the parameter buffer will be T
*ppParameterBuffer = this;
// Only bind the parameters if we haven't already done it
if (*pHAccessor == NULL)
{
ULONG nColumns;
_ParamClass::_GetParamEntries(&nColumns, NULL);
DBBINDING* pBinding = NULL;
ATLTRY(pBinding = new DBBINDING[nColumns]);
if (pBinding == NULL)
return E_OUTOFMEMORY;
hr = _ParamClass::_GetParamEntries(&nColumns, pBinding);
if (SUCCEEDED(hr))
{
// Get the IAccessor from the passed IUnknown
CComPtr<IAccessor> spAccessor;
hr = pCommand->QueryInterface(&spAccessor);
if (SUCCEEDED(hr))
{
hr = BindEntries(pBinding, nColumns, pHAccessor, sizeof(T),
spAccessor);
}
}
delete [] pBinding;
}
return hr;
}
};
///////////////////////////////////////////////////////////////////////////
// CDynamicAccessor
class CDynamicAccessor :
public CAccessorBase
{
public:
CDynamicAccessor()
{
m_nColumns = 0;
m_pColumnInfo = NULL;
m_pStringsBuffer = NULL;
};
~CDynamicAccessor()
{
Close();
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -