624 lines
25 KiB
C++
624 lines
25 KiB
C++
// Start of code for IRowsetChange.h
|
|
// File: IRowsetChange.h
|
|
//
|
|
// This file contains the information for the IMyRowsetChangeImpl class.
|
|
//
|
|
// IMyRowsetChangeImpl inherits from IRowsetChange and does the following:
|
|
//
|
|
// 1. IMyRowsetChangeImpl :: SetData - Performs immediate updates of rowset data
|
|
// 2. IMyRowsetChangeImpl :: CreateRow - Inserts a new default row in the Data Array
|
|
// 3. IMyRowsetChangeImpl :: CreateHRow - Inserts a new row in the Row Handles Array
|
|
// 4. IMyRowsetChangeImpl :: InsertRow - Performs immediate inserts of rowset data
|
|
// 5. IMyRowsetChangeImpl :: DeleteRows - Performs immediate deletes of rowset data
|
|
//
|
|
|
|
// Class IMyRowsetChangeImpl
|
|
#ifndef _ROWSETCHANGE_C822BFE1_C6A1_11d2_AC47_00C04F8DB3D5_H
|
|
#define _ROWSETCHANGE_C822BFE1_C6A1_11d2_AC47_00C04F8DB3D5_H
|
|
|
|
#include "CRow.h"
|
|
|
|
template <class T, class Storage, class RowClass = CSimpleRow>
|
|
class ATL_NO_VTABLE IMyRowsetChangeImpl: public IRowsetChange
|
|
{
|
|
public:
|
|
|
|
// IMyRowsetChangeImpl::SetData( )...
|
|
// Performs Immediate Updates
|
|
|
|
STDMETHOD (SetData)( HROW hRow,HACCESSOR hAccessor, void __RPC_FAR *pData )
|
|
{
|
|
ATLTRACE2(atlTraceDBProvider, 0, "IMyRowsetChangeImpl::SetData\n");
|
|
HRESULT hr;
|
|
T* pT = (T*) this;
|
|
// Putting a Lock on the object in the scope of this member function
|
|
T::ObjectLock cab((T*) this);
|
|
|
|
// A. Validation
|
|
// Check the Row Handle
|
|
if(NULL==hRow)
|
|
{
|
|
ATLTRACE2(atlTraceDBProvider, 0, _T("SetData: Bad hRow\n"));
|
|
return DB_E_BADROWHANDLE;
|
|
}
|
|
// Check the Accessor Handle
|
|
if(NULL==hAccessor)
|
|
{
|
|
ATLTRACE2(atlTraceDBProvider, 0, _T("SetData : Bad hAccessor\n"));
|
|
return DB_E_BADACCESSORHANDLE;
|
|
}
|
|
// Check the Data pointer
|
|
if(NULL== pData)
|
|
{
|
|
ATLTRACE2(atlTraceDBProvider, 0, _T("SetData : Data Pointer was NULL\n"));
|
|
return E_INVALIDARG;
|
|
}
|
|
// Getting the Row structure from the row handle
|
|
// B. Instantiation
|
|
// 1. Instantiate the T::_HRowClass pointer and get the pointer to the row in m_rgRowHandles from the Row handle...
|
|
// m_rgHandles --- for the row handles
|
|
T::_HRowClass *pHRow = pT->m_rgRowHandles.Lookup((T::_HRowClass::KeyType)hRow)->m_value;
|
|
if(!pHRow)
|
|
{
|
|
ATLTRACE2(atlTraceDBProvider, 0, _T("SetData : Could not get Accessor\n"));
|
|
return DB_E_BADROWHANDLE;
|
|
}
|
|
CRow* pRow = pT->m_DBFile.m_Rows[pHRow->m_iRowset];
|
|
if(!pRow)
|
|
{
|
|
ATLTRACE2(atlTraceDBProvider, 0, _T("SetData : Could not get Accessor\n"));
|
|
return DB_E_BADROWHANDLE;
|
|
}
|
|
// 2. Instantiate the Bindings Accessor pointer and get the pointer to the row in m_rgBindings from the Accessor handle...
|
|
// m_rgBindings for the Row Bindings oftype ATLBINDINGS or _BindType
|
|
T::_BindType *pAccessor = pT->m_rgBindings.Lookup(hAccessor)->m_value;
|
|
if(!pAccessor)
|
|
{
|
|
ATLTRACE2(atlTraceDBProvider, 0, _T("SetData : Could not get Accessor\n"));
|
|
return DB_E_BADACCESSORHANDLE;
|
|
}
|
|
// Now all the pointers are obtained ...
|
|
// C. Updating
|
|
// Check for a ROW accessor
|
|
if(!(pAccessor->dwAccessorFlags & DBACCESSOR_ROWDATA))
|
|
{
|
|
ATLTRACE2(atlTraceDBProvider, 0, _T("SetData : Not a Row Accessor\n"));
|
|
return DB_E_BADACCESSORHANDLE;
|
|
}
|
|
// Get pointer to the Row Data from the Data buffer for the handle from m_rgRowData of type _RowsetArrayType
|
|
// Pointer returned is a Storage Class pointer...
|
|
// The index lies in m_iRowset in IRowset
|
|
//The data is taken out as a BYTE array
|
|
|
|
// Get the column info about the Destination rowset i.e. in the Provider Buffer !!!
|
|
ATLCOLUMNINFO* pColInfo; // Column Information structure
|
|
DBORDINAL cCols; // # of cols.
|
|
pColInfo = pT->GetColumnInfo((T*) this,&cCols);
|
|
// D. Transfer data into the Data Buffer for Updation
|
|
DBCOUNTITEM cBindings = pAccessor->cBindings; // Total # of Bindings
|
|
DBBINDING *pBinding = pAccessor->pBindings; // The DBBINDINGS structure pointer...
|
|
HRESULT hrEvent;
|
|
|
|
for(DBCOUNTITEM iBind =0; iBind < cBindings; iBind++)
|
|
{
|
|
DBBINDING *pBindCur = &pBinding[iBind];
|
|
DBORDINAL iCol;
|
|
// To ensure one or zero Bindings per Column
|
|
for(iCol=0; iCol < cCols && pBindCur->iOrdinal != pColInfo[iCol].iOrdinal; iCol++)
|
|
;
|
|
if(iCol == cCols)
|
|
{
|
|
return DB_E_BADORDINAL;
|
|
}
|
|
ATLCOLUMNINFO* pColCur = &pColInfo[iCol];
|
|
if (FAILED(hrEvent = pT->Fire_OnFieldChangeMy((T*)this, hRow, 1,&iCol, DBREASON_COLUMN_SET, DBEVENTPHASE_OKTODO, TRUE)))
|
|
{
|
|
ATLTRACE2(atlTraceDBProvider, 0, "Failed to Fire DBREASON_COLUMN_SET in DBEVENTPHASE_OKTODO phase\n");
|
|
if(hrEvent==S_FALSE)
|
|
return hrEvent;
|
|
}
|
|
if(FAILED(hrEvent = pT->Fire_OnFieldChangeMy((T*)this, hRow, 1,&iCol, DBREASON_COLUMN_SET, DBEVENTPHASE_ABOUTTODO, TRUE)))
|
|
ATLTRACE2(atlTraceDBProvider, 0, "Failed to Fire DBREASON_COLUMN_SET in DBEVENTPHASE_ABOUTTODO phase\n");
|
|
// 1. Build up the 12 parameters to IConvertType::DataConvert( )
|
|
// 1. Types x 2
|
|
DBTYPE wSrcType = pBindCur->wType;
|
|
DBTYPE wDstType = pColCur->wType;
|
|
// 2. Lengths x 2
|
|
//DANK: Changed the following line as it was calculating the dwSrcLength incorrectly. This caused a problem
|
|
// in rowsetviewer when I change the last record, last column value from 300 to 400. IDataConvert would
|
|
// fail with errors occurred
|
|
DBLENGTH dwSrcLength = *((DBLENGTH *)((BYTE*)pData + pBindCur->obLength));
|
|
//ULONG dwDstLength = dwSrcLength; // [in]/[out]
|
|
DBLENGTH dwDstLength = pColCur->ulColumnSize; // [in]/[out]
|
|
// 3. Data ptrs or Offsets from the base ptrs - pRowData (Dst) and pDstData x 2
|
|
BYTE *pSrc = (BYTE*)((BYTE*)pData + pBindCur->obValue); // obValue contains the offset...
|
|
BYTE *pDst = (BYTE*) ((BYTE*) pRow->m_pbProxyData + pColCur->cbOffset);
|
|
// 4. Dst Max Length
|
|
DBLENGTH dwDstMaxLen = pColCur->ulColumnSize;
|
|
// 5. Status x 2
|
|
DBSTATUS dwSrcStatus = *(DBSTATUS*)((BYTE*)pData +pBindCur->obStatus);
|
|
DBSTATUS dwDstStatus;
|
|
// 6. Precision - pBindCur->bPrecision;
|
|
// 7. Scale - pBindCur->bScale;
|
|
// 8. Convert Flags - DATACONVERT_SETDATABEHAVIOUR
|
|
T* pT = (T*) this;
|
|
// Check on DBMEMBER_PROVIDEROWNED or DBMEMBER_PROVIDEROWNED
|
|
BOOL bProvOwn = pBindCur->dwMemOwner == DBMEMOWNER_PROVIDEROWNED;
|
|
bProvOwn;
|
|
// Initialize the Destination Memory to all 0's to remove the junk seen after the string data
|
|
//memset(pDst,0,dwDstMaxLen);
|
|
if(bProvOwn && pColCur->wType == pBindCur->wType)
|
|
// If Provider owned and the types are the same then return the Src pointer to consumer
|
|
pDst = (BYTE*)((BYTE*)pData + pBindCur->obValue);
|
|
else
|
|
{
|
|
// The memory is to be freed by consumer or types differ
|
|
if(FAILED( hr = pT->m_spConvert->DataConvert(
|
|
wSrcType, //* [in] */ DBTYPE wSrcType,
|
|
wDstType, //* [in] */ DBTYPE wDstType,
|
|
dwSrcLength, //* [in] */ ULONG cbSrcLength,
|
|
&dwDstLength, //* [out][in] */ ULONG __RPC_FAR *pcbDstLength,
|
|
pSrc, //* [in] */ void __RPC_FAR *pSrc,
|
|
pDst, //* [out] */ void __RPC_FAR *pDst,
|
|
dwDstMaxLen, //* [in] */ ULONG cbDstMaxLength,
|
|
dwSrcStatus, //* [in] */ DBSTATUS dwSrcStatus,
|
|
&dwDstStatus, //* [out] */ DBSTATUS __RPC_FAR *pdbsStatus,
|
|
pBindCur->bPrecision, //* [in] */ BYTE bPrecision,
|
|
pBindCur->bScale, //* [in] */ BYTE bScale,
|
|
DBDATACONVERT_SETDATABEHAVIOR //* [in] */ DBDATACONVERT dwFlags) = 0;
|
|
)))
|
|
{
|
|
//TODO: Need to handle failure
|
|
if(FAILED(hrEvent = pT->Fire_OnFieldChangeMy((T*)this, hRow, 1,&iCol, DBREASON_COLUMN_SET, DBEVENTPHASE_FAILEDTODO, TRUE)))
|
|
ATLTRACE2(atlTraceDBProvider, 0, "Failed to Fire DBREASON_COLUMN_SET in DBEVENTPHASE_FAILEDTODO phase\n");
|
|
return hr;
|
|
}
|
|
}
|
|
// 2. Write the data to the Storage
|
|
if( FAILED(hr=pT->m_DBFile.UpdateRowImmediate(pRow, pT->m_prgColInfo, pT->m_cCols)) )
|
|
{
|
|
ATLTRACE2(atlTraceDBProvider, 0, _T("SetData : Unsuccessful in writing data to storage\n"));
|
|
// Clean-up the Rows of the Data Buffer
|
|
if(FAILED(hrEvent = pT->Fire_OnFieldChangeMy((T*)this, hRow, 1,&iCol, DBREASON_COLUMN_SET, DBEVENTPHASE_FAILEDTODO, TRUE)))
|
|
ATLTRACE2(atlTraceDBProvider, 0, "Failed to Fire DBREASON_COLUMN_SET in DBEVENTPHASE_FAILEDTODO phase\n");
|
|
return hr;
|
|
}
|
|
|
|
if(FAILED(pT->Fire_OnFieldChangeMy((T*)this, hRow, 1, &iCol, DBREASON_COLUMN_SET, DBEVENTPHASE_SYNCHAFTER, TRUE)))
|
|
ATLTRACE2(atlTraceDBProvider, 0, "Failed to Fire DBREASON_COLUMN_SET in DBEVENTPHASE_SYNCHAFTER phase\n");
|
|
|
|
if(FAILED(pT->Fire_OnFieldChangeMy((T*)this, hRow, 1, &iCol, DBREASON_COLUMN_SET, DBEVENTPHASE_DIDEVENT, TRUE)))
|
|
ATLTRACE2(atlTraceDBProvider, 0, "Failed to Fire DBREASON_COLUMN_SET in DBEVENTPHASE_DIDEVENT phase\n");
|
|
|
|
if(FAILED(pT->Fire_OnFieldChangeMy((T*)this, hRow, 1, &iCol, DBREASON_COLUMN_RECALCULATED, DBEVENTPHASE_DIDEVENT, TRUE)))
|
|
ATLTRACE2(atlTraceDBProvider, 0, "Failed to Fire DBREASON_COLUMN_SET in DBEVENTPHASE_DIDEVENT phase\n");
|
|
}
|
|
return S_OK;
|
|
}
|
|
|
|
// IRowsetImpl::CreateHRow( )
|
|
// Helper function to create a new entry in the m_rgRowHandles
|
|
HRESULT CreateHRow(DBBYTEOFFSET lRowsOffset, HROW *phRow)
|
|
{
|
|
T* pT = (T*) this;
|
|
T::_HRowClass* pRow = NULL;
|
|
ATLASSERT(lRowsOffset >= 0);
|
|
T::_HRowClass::KeyType key = lRowsOffset+1;
|
|
ATLASSERT(key > 0);
|
|
|
|
CAtlMap<RowClass::KeyType, RowClass*>::CPair* pPair = pT->m_rgRowHandles.Lookup(key);
|
|
if (pPair)
|
|
pRow = pPair->m_value;
|
|
if (pRow == NULL)
|
|
{
|
|
ATLTRY(pRow = new T::_HRowClass(lRowsOffset)) // Copy constructor
|
|
if (pRow == NULL)
|
|
return E_OUTOFMEMORY;
|
|
if (!pT->m_rgRowHandles.SetAt(key, pRow))
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
// Doing the AddRef here
|
|
pRow->AddRefRow();
|
|
pT->m_bReset = false;
|
|
if(phRow != NULL)
|
|
*phRow = (HROW)key;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
// IRowsetImpl::CreateHRow( )
|
|
// Helper function to create a new entry in the Data array to store a default row
|
|
HRESULT CreateRecord(DBROWCOUNT &cRowsObtained, HROW *phRow)
|
|
{
|
|
ATLTRACE2(atlTraceDBProvider, 0, "IMyRowsetChangeImpl::CreateRecord\n");
|
|
HRESULT hr = S_OK;
|
|
T* pT = (T*) this;
|
|
|
|
CRow* pRow = new CRow(); // A New blank row inserted into the MM file
|
|
if(pRow == NULL)
|
|
return E_OUTOFMEMORY;
|
|
|
|
// Need to Set the BookMark appropriately after creating the Row
|
|
// Get the last Bookmark
|
|
size_t tmpSize = pT->m_DBFile.m_Rows.GetCount();
|
|
ULONG newBkMrk;
|
|
if (0 != tmpSize)
|
|
newBkMrk = pT->m_DBFile.m_Rows[tmpSize-1]->m_bmk + 1;
|
|
else // When there are 0 records
|
|
newBkMrk = 1;
|
|
|
|
// Create new Row in the Row Array
|
|
ATLCOLUMNINFO* pColInfo; // Column Information structure
|
|
DBORDINAL cCols; // # of cols.
|
|
pColInfo =pT-> GetColumnInfo( pT,&cCols);
|
|
if (!pT->m_DBFile.AddRow(pRow, pColInfo, cCols)) // This will add the CRow object to the file and initialize it
|
|
{
|
|
ATLTRACE2(atlTraceDBProvider, 0, _T("InsertRow : Unsuccessful in creating a Row\n"));
|
|
// The Cleanup
|
|
phRow = NULL;
|
|
if(FAILED(pT->Fire_OnRowChangeMy((T*)this, 1, phRow, DBREASON_ROW_INSERT, DBEVENTPHASE_FAILEDTODO, TRUE)))
|
|
ATLTRACE2(atlTraceDBProvider, 0, "Failed to Fire DBREASON_ROW_INSERT in DBEVENTPHASE_FAILEDTODO phase\n");
|
|
return E_FAIL;
|
|
}
|
|
|
|
// Set the new BookMark
|
|
if(newBkMrk)
|
|
pT->m_DBFile.m_Rows[tmpSize]->m_bmk= newBkMrk;
|
|
|
|
// Add the data to the File
|
|
if( FAILED(hr = pT->m_DBFile.InsertRowImmediate(pRow, pColInfo, cCols,false)) )
|
|
{
|
|
ATLTRACE2(atlTraceDBProvider, 0, _T("InsertRow : Unsuccessful in converting data\n"));
|
|
// Clean-up the Rows of the Data Buffer
|
|
for (size_t i=0; i<pT->m_DBFile.m_Rows.GetCount(); ++i)
|
|
{
|
|
if (pT->m_DBFile.m_Rows[i] == pRow)
|
|
pT->m_DBFile.m_Rows.RemoveAt(i);
|
|
}
|
|
pT->m_iRowset--;
|
|
phRow = NULL;
|
|
if(FAILED(pT->Fire_OnRowChangeMy((T*)this, 1, phRow, DBREASON_ROW_INSERT, DBEVENTPHASE_FAILEDTODO, TRUE)))
|
|
ATLTRACE2(atlTraceDBProvider, 0, "Failed to Fire DBREASON_ROW_INSERT in DBEVENTPHASE_FAILEDTODO phase\n");
|
|
return hr;
|
|
}
|
|
|
|
//Add the Row into the m_rgRowHandles
|
|
if((hr=pT->CreateHRow(pT->m_DBFile.m_Rows.GetCount() - 1, phRow)) != S_OK)
|
|
{
|
|
ATLTRACE2(atlTraceDBProvider, 0, _T("InsertRow : Unsuccessful in creating a Row Handle\n"));
|
|
// The Cleanup
|
|
phRow = NULL;
|
|
if(FAILED(pT->Fire_OnRowChangeMy((T*)this, 1, phRow, DBREASON_ROW_INSERT, DBEVENTPHASE_FAILEDTODO, TRUE)))
|
|
ATLTRACE2(atlTraceDBProvider, 0, "Failed to Fire DBREASON_ROW_INSERT in DBEVENTPHASE_FAILEDTODO phase\n");
|
|
return hr;
|
|
}
|
|
|
|
if(FAILED(pT->Fire_OnRowChangeMy((T*)this, 1, phRow, DBREASON_ROW_INSERT, DBEVENTPHASE_SYNCHAFTER, TRUE)))
|
|
ATLTRACE2(atlTraceDBProvider, 0, "Failed to Fire DBREASON_ROW_INSERT in DBEVENTPHASE_SYNCHAFTER phase\n");
|
|
|
|
if(FAILED(pT->Fire_OnRowChangeMy((T*)this, 1, phRow, DBREASON_ROW_INSERT, DBEVENTPHASE_DIDEVENT, TRUE)))
|
|
ATLTRACE2(atlTraceDBProvider, 0, "Failed to Fire DBREASON_ROW_INSERT in DBEVENTPHASE_DIDEVENT phase\n");
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
// IRowsetImpl::InsertRow( )
|
|
// Performing Immediate Inserts...
|
|
|
|
STDMETHOD (InsertRow)(
|
|
/* [in] */ HCHAPTER hReserved,
|
|
/* [in] */ HACCESSOR hAccessor,
|
|
/* [in] */ void __RPC_FAR *pData,
|
|
/* [out] */ HROW __RPC_FAR *phRow)
|
|
{
|
|
ATLTRACE2(atlTraceDBProvider, 0, "IMyRowsetChangeImpl::InsertRow\n");
|
|
HRESULT hr;
|
|
T* pT = (T*) this;
|
|
// Putting a Lock on the object in the scope of this member function
|
|
T::ObjectLock cab((T*) this);
|
|
|
|
HRESULT hrEvent = S_OK;
|
|
ULONG cRows = 1;
|
|
|
|
// A. Validate
|
|
|
|
// Chapters not supported
|
|
if(DB_NULL_HCHAPTER != hReserved)
|
|
return DB_E_NOTSUPPORTED;
|
|
|
|
if (FAILED(hrEvent = pT->Fire_OnRowChangeMy((T*)this, cRows, phRow, DBREASON_ROW_INSERT, DBEVENTPHASE_OKTODO, TRUE)))
|
|
{
|
|
ATLTRACE2(atlTraceDBProvider, 0, "Failed to Fire DBREASON_ROW_INSERT in DBEVENTPHASE_OKTODO phase\n");
|
|
if(hrEvent==S_FALSE)
|
|
return hrEvent;
|
|
}
|
|
// Check the Accessor Handle
|
|
if(NULL==hAccessor)
|
|
{
|
|
ATLTRACE2(atlTraceDBProvider, 0, _T("InsertRow : Bad hAccessor\n"));
|
|
return DB_E_BADACCESSORHANDLE;
|
|
}
|
|
// Check the Data pointer
|
|
if(NULL== pData)
|
|
{
|
|
ATLTRACE2(atlTraceDBProvider, 0, _T("InsertRow : Data Pointer was NULL\n"));
|
|
DBROWCOUNT cRowsObtained=0;
|
|
if(FAILED(pT->Fire_OnRowChangeMy((T*)this, cRows, phRow, DBREASON_ROW_INSERT, DBEVENTPHASE_ABOUTTODO, TRUE)))
|
|
ATLTRACE2(atlTraceDBProvider, 0, "Failed to Fire DBREASON_ROW_INSERT in DBEVENTPHASE_ABOUTTODO phase\n");
|
|
// Create a new record if the pData pointer is NULL
|
|
// The ADO Data Grid asks for a NULL or Default row during insertions
|
|
return CreateRecord(cRowsObtained, phRow);
|
|
}
|
|
|
|
// B. Instantiation
|
|
|
|
// 1. Instantiate the Bindings Accessor pointer and get the pointer to the row in m_rgBindings from the Accessor handle...
|
|
// m_rgBindings for the Row Bindings oftype ATLBINDINGS or _BindType
|
|
T::_BindType *pAccessor = pT->m_rgBindings.Lookup(hAccessor)->m_value;
|
|
if(!pAccessor)
|
|
{
|
|
ATLTRACE2(atlTraceDBProvider, 0, _T("InsertRow : Could not get Accessor\n"));
|
|
return DB_E_BADACCESSORHANDLE;
|
|
}
|
|
|
|
//C. Preparing for Insertion
|
|
|
|
// Check for a ROW accessor
|
|
if(!(pAccessor->dwAccessorFlags & DBACCESSOR_ROWDATA))
|
|
{
|
|
ATLTRACE2(atlTraceDBProvider, 0, _T("InsertRow : Not a Row Accessor\n"));
|
|
return DB_E_BADACCESSORHANDLE;
|
|
}
|
|
|
|
// Create a new row in the Row Array
|
|
CRow * pRow = new CRow;
|
|
ATLCOLUMNINFO* pColInfo; // Column Information structure
|
|
DBORDINAL cCols; // # of cols.
|
|
pColInfo =pT-> GetColumnInfo( pT,&cCols);
|
|
|
|
|
|
// Need to Set the BookMark appropriately after creating the Row
|
|
// Get the last Bookmark
|
|
size_t tmpSize = pT->m_DBFile.m_Rows.GetCount();
|
|
DWORD newBkMrk;
|
|
if (0 != tmpSize)
|
|
newBkMrk = pT->m_DBFile.m_Rows[tmpSize-1]->m_bmk + 1;
|
|
else // When there are 0 records
|
|
newBkMrk = 1;
|
|
|
|
// This will add the CRow object to the file and initialize it
|
|
if (!pT->m_DBFile.AddRow(pRow, pColInfo, cCols))
|
|
{
|
|
ATLTRACE2(atlTraceDBProvider, 0, _T("InsertRow : Unsuccessful in creating a Row\n"));
|
|
// The Cleanup
|
|
phRow = NULL;
|
|
if(FAILED(pT->Fire_OnRowChangeMy((T*)this, 1, phRow, DBREASON_ROW_INSERT, DBEVENTPHASE_FAILEDTODO, TRUE)))
|
|
ATLTRACE2(atlTraceDBProvider, 0, "Failed to Fire DBREASON_ROW_INSERT in DBEVENTPHASE_FAILEDTODO phase\n");
|
|
return E_FAIL;
|
|
}
|
|
|
|
// Assign proxy buffer to the destination pointer
|
|
BYTE * pRowData = pRow->m_pbProxyData;
|
|
|
|
if(FAILED(pT->Fire_OnRowChangeMy((T*)this, cRows, phRow, DBREASON_ROW_INSERT, DBEVENTPHASE_ABOUTTODO, TRUE)))
|
|
ATLTRACE2(atlTraceDBProvider, 0, "Failed to Fire DBREASON_ROW_INSERT in DBEVENTPHASE_ABOUTTODO phase\n");
|
|
|
|
//D. Inserting the Row
|
|
|
|
DBCOUNTITEM cBindings = pAccessor->cBindings; // Total # of Bindings
|
|
DBBINDING *pBinding = pAccessor->pBindings; // The DBBINDINGS structure pointer...
|
|
for(DBCOUNTITEM iBind =0; iBind < cBindings; iBind++)
|
|
{
|
|
DBBINDING *pBindCur = &pBinding[iBind];
|
|
// To ensure one or zero Bindings per Column
|
|
DBORDINAL iCol;
|
|
for(iCol=0; iCol < cCols && pBindCur->iOrdinal != pColInfo[iCol].iOrdinal; iCol++);
|
|
if(iCol == cCols)
|
|
{
|
|
if(FAILED(pT->Fire_OnRowChangeMy((T*)this, cRows, phRow, DBREASON_ROW_INSERT, DBEVENTPHASE_FAILEDTODO, TRUE)))
|
|
ATLTRACE2(atlTraceDBProvider, 0, "Failed to Fire DBREASON_ROW_INSERT in DBEVENTPHASE_FAILEDTODO phase\n");
|
|
return DB_E_BADORDINAL;
|
|
}
|
|
ATLCOLUMNINFO* pColCur = &pColInfo[iCol];
|
|
// Build up the 12 parameters to IConvertType::DataConvert( )
|
|
// 1. Types x 2
|
|
DBTYPE wSrcType = pBindCur->wType;
|
|
DBTYPE wDstType = pColCur->wType;
|
|
// 2. Lengths x 2
|
|
DBLENGTH dwSrcLength = *((DBLENGTH *)((BYTE*)pData + pBindCur->obLength));
|
|
DBLENGTH dwDstLength = pColCur->ulColumnSize; // [in]/[out]
|
|
// 3. Data ptrs or Offsets from the base ptrs - pRowData (Dst) and pDstData x 2
|
|
BYTE *pSrc = (BYTE*)((BYTE*)pData + pBindCur->obValue); // obValue contains the offset...
|
|
BYTE *pDst = (BYTE*) ((BYTE*) pRowData + pColCur->cbOffset);
|
|
// 4. Dst Max Length
|
|
DBLENGTH dwDstMaxLen = pColCur->ulColumnSize;
|
|
// 5. Status x 2
|
|
DBSTATUS dwSrcStatus = *(DBSTATUS*)((BYTE*)pData+pBindCur->obStatus);
|
|
DWORD dwDstStatus;
|
|
// 6. Precision - pBindCur->bPrecision;
|
|
// 7. Scale - pBindCur->bScale;
|
|
// 8. Convert Flags - DATACONVERT_SETDATABEHAVIOUR
|
|
// Check on DBMEMBER_PROVIDEROWNED or DBMEMBER_PROVIDEROWNED
|
|
BOOL bProvOwn = pBindCur->dwMemOwner == DBMEMOWNER_PROVIDEROWNED;
|
|
bProvOwn;
|
|
|
|
if(bProvOwn && pColCur->wType == pBindCur->wType)
|
|
// If Provider owned and the types are the same then return the Src pointer to consumer
|
|
pDst = (BYTE*)((BYTE*)pData + pBindCur->obValue);
|
|
else
|
|
{
|
|
// The memory is to be freed by consumer or types differ
|
|
if(FAILED( hr = pT->m_spConvert->DataConvert(
|
|
wSrcType, //* [in] */ DBTYPE wSrcType,
|
|
wDstType, //* [in] */ DBTYPE wDstType,
|
|
dwSrcLength, //* [in] */ ULONG cbSrcLength,
|
|
&dwDstLength, //* [out][in] */ ULONG __RPC_FAR *pcbDstLength,
|
|
pSrc, //* [in] */ void __RPC_FAR *pSrc,
|
|
pDst, //* [out] */ void __RPC_FAR *pDst,
|
|
dwDstMaxLen, //* [in] */ ULONG cbDstMaxLength,
|
|
dwSrcStatus, ///* [in] */ DBSTATUS dbsSrcStatus,
|
|
&dwDstStatus, //* [out] */ DBSTATUS __RPC_FAR *pdbsStatus,
|
|
pBindCur->bPrecision, //* [in] */ BYTE bPrecision,
|
|
pBindCur->bScale, //* [in] */ BYTE bScale,
|
|
DBDATACONVERT_SETDATABEHAVIOR //* [in] */ DBDATACONVERT dwFlags) = 0;
|
|
)))
|
|
{
|
|
ATLTRACE2(atlTraceDBProvider, 0, _T("InsertRow : Unsuccessful in converting data\n"));
|
|
// The Cleanup...
|
|
pT->m_iRowset--;
|
|
phRow = NULL;
|
|
if(FAILED(pT->Fire_OnRowChangeMy((T*)this, cRows, phRow, DBREASON_ROW_INSERT, DBEVENTPHASE_FAILEDTODO, TRUE)))
|
|
ATLTRACE2(atlTraceDBProvider, 0, "Failed to Fire DBREASON_ROW_INSERT in DBEVENTPHASE_FAILEDTODO phase\n");
|
|
return hr | E_FAIL;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Set the new BookMark
|
|
if(newBkMrk)
|
|
pT->m_DBFile.m_Rows[tmpSize]->m_bmk= newBkMrk;
|
|
|
|
// Insert the data into the Storage from
|
|
//now that the data has been transfer to the proxy buffer, store to file
|
|
if( FAILED(hr = pT->m_DBFile.InsertRowImmediate(pRow, pColInfo, cCols,true)) )
|
|
{
|
|
ATLTRACE2(atlTraceDBProvider, 0, _T("InsertRow : Unsuccessful in converting data\n"));
|
|
// Clean-up the Rows of the Data Buffer
|
|
for (size_t i=0; i<pT->m_DBFile.m_Rows.GetCount(); ++i)
|
|
{
|
|
if (pT->m_DBFile.m_Rows[i] == pRow)
|
|
pT->m_DBFile.m_Rows.RemoveAt(i);
|
|
}
|
|
pT->m_iRowset--;
|
|
phRow = NULL;
|
|
if(FAILED(pT->Fire_OnRowChangeMy((T*)this, cRows, phRow, DBREASON_ROW_INSERT, DBEVENTPHASE_FAILEDTODO, TRUE)))
|
|
ATLTRACE2(atlTraceDBProvider, 0, "Failed to Fire DBREASON_ROW_INSERT in DBEVENTPHASE_FAILEDTODO phase\n");
|
|
return hr;
|
|
}
|
|
|
|
//Add the Row into the m_rgRowHandles
|
|
if((hr=pT->CreateHRow(pT->m_DBFile.m_Rows.GetCount() - 1, phRow)) != S_OK)
|
|
{
|
|
ATLTRACE2(atlTraceDBProvider, 0, _T("InsertRow : Unsuccessful in creating a Row Handle\n"));
|
|
// Clean-up the Rows of the Data Buffer
|
|
for (size_t i=0; i<pT->m_DBFile.m_Rows.GetCount(); ++i)
|
|
{
|
|
if (pT->m_DBFile.m_Rows[i] == pRow)
|
|
pT->m_DBFile.m_Rows.RemoveAt(i);
|
|
}
|
|
// The Cleanup
|
|
pT->m_iRowset--;
|
|
phRow = NULL;
|
|
if(FAILED(pT->Fire_OnRowChangeMy((T*)this, 1, phRow, DBREASON_ROW_INSERT, DBEVENTPHASE_FAILEDTODO, TRUE)))
|
|
ATLTRACE2(atlTraceDBProvider, 0, "Failed to Fire DBREASON_ROW_INSERT in DBEVENTPHASE_FAILEDTODO phase\n");
|
|
return hr;
|
|
}
|
|
|
|
if(FAILED(pT->Fire_OnRowChangeMy((T*)this, cRows, phRow, DBREASON_ROW_INSERT, DBEVENTPHASE_SYNCHAFTER, TRUE)))
|
|
ATLTRACE2(atlTraceDBProvider, 0, "Failed to Fire DBREASON_ROW_INSERT in DBEVENTPHASE_SYNCHAFTER phase\n");
|
|
|
|
if(FAILED(pT->Fire_OnRowChangeMy((T*)this, cRows, phRow, DBREASON_ROW_INSERT, DBEVENTPHASE_DIDEVENT, TRUE)))
|
|
ATLTRACE2(atlTraceDBProvider, 0, "Failed to Fire DBREASON_ROW_INSERT in DBEVENTPHASE_DIDEVENT phase\n");
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
// IRowsetImpl: DeleteRows( )
|
|
// Performing Immediate deletes
|
|
|
|
STDMETHOD (DeleteRows)(
|
|
/* [in] */ HCHAPTER hReserved,
|
|
/* [in] */ DBCOUNTITEM cRows, // Total number of rows to be deleted
|
|
/* [size_is][in] */ const HROW __RPC_FAR rghRows[ ], //An array of handles of the rows to be deleted
|
|
/* [size_is][out] */ DBROWSTATUS __RPC_FAR rgRowStatus[ ]) //An array with cRows elements in which to return values indicating the status of each row specified in rghRows
|
|
{
|
|
ATLTRACE2(atlTraceDBProvider, 0, "IMyRowsetChangeImpl::DeleteRows\n");
|
|
T* pT = (T*) this;
|
|
T::ObjectLock cab((T*) pT);
|
|
HRESULT hr = S_OK;
|
|
|
|
HRESULT hrEvent = S_OK;
|
|
if(FAILED(pT->Fire_OnRowChangeMy((T*)this, cRows, rghRows, DBREASON_ROW_DELETE, DBEVENTPHASE_OKTODO, TRUE)))
|
|
{
|
|
ATLTRACE2(atlTraceDBProvider, 0, "Failed to Fire DBREASON_ROW_DELETE in DBEVENTPHASE_OKTODO phase\n");
|
|
if(hrEvent==S_FALSE)
|
|
return hrEvent;
|
|
}
|
|
// Putting a Lock on the object in the scope of this member function
|
|
|
|
// A. Validation
|
|
|
|
if(DB_NULL_HCHAPTER != hReserved)
|
|
{
|
|
ATLTRACE2(atlTraceDBProvider, 0, "IMyRowsetChangeImpl::DeleteRows: Chapters are not supported\n");
|
|
return DB_E_NOTSUPPORTED;
|
|
}
|
|
|
|
if(cRows <= 0)
|
|
{
|
|
ATLTRACE2(atlTraceDBProvider, 0, "IMyRowsetChangeImpl::DeleteRows: Too few Rows\n");
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
if(NULL == rghRows)
|
|
{
|
|
ATLTRACE2(atlTraceDBProvider, 0, "IMyRowsetChangeImpl::DeleteRows: Too few Row Handles\n");
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
if(FAILED(pT->Fire_OnRowChangeMy((T*)this, cRows, rghRows, DBREASON_ROW_DELETE, DBEVENTPHASE_ABOUTTODO, TRUE)))
|
|
ATLTRACE2(atlTraceDBProvider, 0, "Failed to Fire DBREASON_ROW_DELETE in DBEVENTPHASE_ABOUTTODO phase\n");
|
|
|
|
// B. Deleting the rows
|
|
// Delete Rows dealing only with the m_rgRowData
|
|
// ADO client Release the rows appropriately
|
|
// The process of Deleting the rows
|
|
|
|
for(DBCOUNTITEM i=0; i<cRows; i++)
|
|
{
|
|
// Find the Row from the handle
|
|
T::_HRowClass *pHRow = pT->m_rgRowHandles.Lookup((T::_HRowClass::KeyType)rghRows[i])->m_value;
|
|
if(!pHRow)
|
|
{
|
|
ATLTRACE2(atlTraceDBProvider, 0, _T("IMyRowsetChangeImpl::DeleteRows: Bad Row Handle\n"));
|
|
if(rgRowStatus) rgRowStatus[i] = DBROWSTATUS_E_INVALID;
|
|
if(FAILED(pT->Fire_OnRowChangeMy((T*)this, cRows, rghRows, DBREASON_ROW_DELETE, DBEVENTPHASE_FAILEDTODO, TRUE)))
|
|
ATLTRACE2(atlTraceDBProvider, 0, "Failed to Fire DBREASON_ROW_DELETE in DBEVENTPHASE_FAILEDTODO phase\n");
|
|
return DB_E_BADROWHANDLE;
|
|
}
|
|
|
|
// The marking of the rows to be deleted is to be from the Buffer (m_rgRowData) itself
|
|
// 1. rghRows[i] - handle of therow to deleted
|
|
// 2. phRow - CSimpleRow in m_rgRowHandles whose m_aKey = rghRows[i]
|
|
// 3. pHRow->m_iRowset - index of the row in the Data array
|
|
// 4. pT->m_DBFile.m_Rows - the Data array
|
|
hr = pT->m_DBFile.DeleteRowImmediate(pT->m_DBFile.m_Rows[pHRow->m_iRowset]);
|
|
if (FAILED(hr))
|
|
{
|
|
ATLTRACE2(atlTraceDBProvider, 0, _T("IMyRowsetChangeImpl::DeleteRows: Unable to remove Row \n"));
|
|
if(rgRowStatus) rgRowStatus[i] = DBROWSTATUS_E_FAIL;
|
|
if(FAILED(pT->Fire_OnRowChangeMy((T*)this, cRows, rghRows, DBREASON_ROW_DELETE, DBEVENTPHASE_FAILEDTODO, TRUE)))
|
|
ATLTRACE2(atlTraceDBProvider, 0, "Failed to Fire DBREASON_ROW_DELETE in DBEVENTPHASE_FAILEDTODO phase\n");
|
|
return DB_S_ERRORSOCCURRED;
|
|
}
|
|
|
|
if (rgRowStatus)
|
|
rgRowStatus[i] = DBROWSTATUS_S_OK;
|
|
|
|
}
|
|
|
|
if(FAILED(pT->Fire_OnRowChangeMy((T*)this, cRows, rghRows, DBREASON_ROW_DELETE, DBEVENTPHASE_SYNCHAFTER, TRUE)))
|
|
ATLTRACE2(atlTraceDBProvider, 0, "Failed to Fire DBREASON_ROW_DELETE in DBEVENTPHASE_SYNCHAFTER phase\n");
|
|
|
|
if(FAILED(pT->Fire_OnRowChangeMy((T*)this, cRows, rghRows, DBREASON_ROW_DELETE, DBEVENTPHASE_DIDEVENT, TRUE)))
|
|
ATLTRACE2(atlTraceDBProvider, 0, "Failed to Fire DBREASON_ROW_DELETE in DBEVENTPHASE_DIDEVENT phase\n");
|
|
|
|
return hr;
|
|
}
|
|
};
|
|
#endif
|
|
|
|
// End of code for IRowsetChange.h
|