2025-11-28 00:35:46 +09:00

515 lines
15 KiB
C++

//--------------------------------------------------------------------
// Microsoft OLE DB Sample Provider
// (C) Copyright 1991 - 1999 Microsoft Corporation. All Rights Reserved.
//
// @doc
//
// @module ROWCHNG.CPP | IRowsetChange interface implementation
//
//
// Includes ------------------------------------------------------------------
#include "headers.h"
// Code ----------------------------------------------------------------------
// IRowsetChange specific methods
// CImpIRowsetChange::SetData ------------------------------------------------
//
// @mfunc Sets new data values into fields of a row.
//
// @rdesc HRESULT
// @flag S_OK | The method succeeded
// @flag E_OUTOFMEMORY | Out of memory
// @flag DB_E_BADACCESSORHANDLE | Bad accessor handle
// @flag DB_E_READONLYACCESSOR | Tried to write through a read-only accessor
// @flag DB_E_BADROWHANDLE | Invalid row handle
// @flag E_INVALIDARG | pData was NULL
// @flag E_FAIL | Provider-specific error
// @flag OTHER | Other HRESULTs returned by called functions
//
STDMETHODIMP CImpIRowsetChange::SetData
(
HROW hRow, //@parm IN | Handle of the row in which to set the data
HACCESSOR hAccessor, //@parm IN | Handle to the accessor to use
void* pData //@parm IN | Pointer to the data
)
{
DBORDINAL cCols;
DBCOUNTITEM cBind;
BYTE* pbProvRow;
HRESULT hr;
DBCOUNTITEM cBindings;
DBBINDING* pBinding;
DBCOUNTITEM cErrorCount;
DBTYPE dwSrcType;
DBTYPE dwDstType;
DWORD dwPart;
ULONG dwSrcLength;
DWORD dwSrcStatus;
void* pSrc;
void* pDst;
DBLENGTH* pdwDstLength;
DBLENGTH cbDstMaxLength;
DWORD* pdwDstStatus;
PCOLUMNDATA pColumnData;
PACCESSOR paccessor = NULL;
BYTE* rgbRowDataSave = NULL;
DBCOLUMNINFO * rgdbcolumninfo = NULL;
// Is row handle right?
assert( m_pObj->m_prowbitsIBuffer );
if( (m_pObj->m_prowbitsIBuffer)->IsSlotSet( (ULONG)hRow ) != S_OK )
return( DB_E_BADROWHANDLE );
// Check the Accessor Handle
assert( m_pObj->m_pextbufferAccessor );
if( FAILED(m_pObj->m_pextbufferAccessor->GetItemOfExtBuffer(hAccessor, &paccessor)))
return( DB_E_BADACCESSORHANDLE );
// Ensure a source of data.
assert( paccessor );
if( paccessor->cBindings && !pData )
return( E_INVALIDARG );
pbProvRow = (BYTE *)(m_pObj->GetRowBuff((DBCOUNTITEM) hRow, TRUE ));
// Is row handle deleted?
if( m_pObj->m_pFileio->IsDeleted((DBBKMARK) ((PROWBUFF) pbProvRow)->pbBmk ) == S_OK )
return( DB_E_DELETEDROW );
rgbRowDataSave = (BYTE *) malloc( m_pObj->m_cbTotalRowSize );
if( !rgbRowDataSave )
return( E_OUTOFMEMORY );
// Save the row.
memcpy( rgbRowDataSave, pbProvRow, m_pObj->m_cbTotalRowSize );
cBindings = paccessor->cBindings;
pBinding = paccessor->rgBindings;
// Apply accessor to data.
rgdbcolumninfo = m_pObj->m_pFileio->GetColInfo();
for (cBind = 0, cErrorCount = 0; cBind < cBindings; cBind++)
{
cCols = pBinding[cBind].iOrdinal;
// make sure column number is in range
if( cCols < 1 || cCols > m_pObj->m_cCols )
return( DB_E_BADORDINAL );
pColumnData = m_pObj->m_pFileio->GetColumnData(cCols, (ROWBUFF *)pbProvRow);
dwSrcType = pBinding[cBind].wType;
pDst = &(pColumnData->bData);
pdwDstLength = &(pColumnData->uLength);
pdwDstStatus = &(pColumnData->dwStatus);
cbDstMaxLength = pBinding[cBind].cbMaxLen;
dwPart = pBinding[cBind].dwPart;
dwDstType = rgdbcolumninfo[cCols].wType;
// Get the Length
if( dwPart & DBPART_LENGTH )
dwSrcLength = *(ULONG *)((BYTE*)pData + pBinding[cBind].obLength);
else
dwSrcLength = 0;
// Get the Status
if( dwPart & DBPART_STATUS )
dwSrcStatus = *(ULONG *)((BYTE*)pData + pBinding[cBind].obStatus);
else
dwSrcStatus = DBSTATUS_S_OK;
// Check the Status for DBSTATUS_S_DEFAULT
if( dwSrcStatus == DBSTATUS_S_DEFAULT )
dwSrcStatus = DBSTATUS_S_ISNULL;
// Check the Status for DBSTATUS_S_IGNORE
if( dwSrcStatus == DBSTATUS_S_IGNORE ||
dwSrcStatus == DBSTATUS_S_ISNULL )
continue;
// Check the Status of the value being sent in
if( dwSrcStatus != DBSTATUS_S_OK )
{
*(ULONG *)((BYTE*)pData + pBinding[cBind].obStatus) = DBSTATUS_E_BADSTATUS;
cErrorCount++;
continue;
}
// Get the Value
if( (dwPart & DBPART_VALUE) == 0 )
{
if( dwPart & DBPART_STATUS )
*(ULONG *)((BYTE*)pData + pBinding[cBind].obStatus) = DBSTATUS_E_UNAVAILABLE;
cErrorCount++;
continue;
}
else
{
pSrc = (void *) ((BYTE*) pData + pBinding[cBind].obValue);
}
// Check to see if we have a DC
if( !g_pIDataConvert )
return( E_FAIL );
hr = g_pIDataConvert->DataConvert(
dwSrcType,
dwDstType,
dwSrcLength,
pdwDstLength,
pSrc,
pDst,
cbDstMaxLength,
dwSrcStatus,
pdwDstStatus,
pBinding[cBind].bPrecision, // bPrecision for conversion to DBNUMERIC
pBinding[cBind].bScale, // bScale for conversion to DBNUMERIC
(DBDATACONVERT_SETDATABEHAVIOR |
(!dwSrcLength ? DBDATACONVERT_LENGTHFROMNTS : 0)));
if( dwPart & DBPART_STATUS )
*(ULONG *)((BYTE*)pData + pBinding[cBind].obStatus) = *pdwDstStatus;
// fatal error
if( FAILED( hr ) && hr != DB_E_ERRORSOCCURRED )
return hr;
// rounding or truncation or can't coerce
if( hr != S_OK )
cErrorCount++;
}
// Carry out the update.
if( FAILED( m_pObj->m_pFileio->UpdateRow((DBBKMARK) ((PROWBUFF) pbProvRow)->pbBmk, pbProvRow, UPDATE )) )
{
// Restore the row to its previous state
memcpy( pbProvRow, rgbRowDataSave, m_pObj->m_cbTotalRowSize );
free( rgbRowDataSave );
return( E_FAIL );
}
free( rgbRowDataSave );
// If everything went OK except errors in rows use DB_S_ERRORSOCCURRED.
return cErrorCount ? ( cErrorCount < cBindings ) ?
( DB_S_ERRORSOCCURRED ) : ( DB_E_ERRORSOCCURRED ) : ( S_OK );
}
// CImpIRowsetChange::DeleteRows ---------------------------------------
//
// @mfunc Deletes rows from the provider. If Errors on individual rows
// occur, the DBERRORINFO array is updated to reflect the error and S_FALSE
// is returned instead of S_OK.
//
// @rdesc HRESULT indicating the status of the method
// @Flag S_OK | All row handles deleted
// @Flag DB_S_ERRORSOCCURRED | Some, but not all, row handles deleted
// @Flag E_INVALIDARG | Arguments did not match spec.
// @Flag E_OUTOFMEMORY | Could not allocated error array
//
STDMETHODIMP CImpIRowsetChange::DeleteRows
(
HCHAPTER hChapter, //@parm IN | The Chapter handle.
DBCOUNTITEM cRows, //@parm IN | Number of rows to delete
const HROW rghRows[], //@parm IN | Array of handles to delete
DBROWSTATUS rgRowStatus[] //@parm OUT | Error information
)
{
DBCOUNTITEM chRow = 0L;
DBCOUNTITEM cErrors = 0L;
BYTE* pbProvRow = NULL;
// If No Row handle, just return.
if( cRows == 0 )
return( S_OK );
// Check for Invalid Arguments
if ( !rghRows )
return( E_INVALIDARG );
// Process row handles
while (chRow < cRows)
{
if( rgRowStatus )
rgRowStatus[chRow] = DBROWSTATUS_S_OK;
// Is row handle valid
if( (m_pObj->m_prowbitsIBuffer)->IsSlotSet( (ULONG)rghRows[chRow]) != S_OK )
{
// Log Error
if( rgRowStatus )
rgRowStatus[chRow]= DBROWSTATUS_E_INVALID;
cErrors++;
chRow++;
continue;
}
// Get RowBuffer to look at which row this applies to
pbProvRow = (BYTE *) (m_pObj->GetRowBuff((DBCOUNTITEM) rghRows[chRow], TRUE ));
// Has row already been deleted
// S_OK means deleted
if( m_pObj->m_pFileio->IsDeleted((DBBKMARK) ((PROWBUFF) pbProvRow)->pbBmk ) == S_OK )
{
if( rgRowStatus )
rgRowStatus[chRow] = DBROWSTATUS_E_DELETED;
cErrors++;
chRow++;
continue;
}
// Delete the Row,
if( m_pObj->m_pFileio->DeleteRow((DBBKMARK) ((PROWBUFF) pbProvRow)->pbBmk) != S_OK )
{
// Some better decision as to what rowstatus to set could be done here..
if( rgRowStatus )
rgRowStatus[chRow] = DBROWSTATUS_E_FAIL;
cErrors++;
chRow++;
continue;
}
// Delete worked correctly
chRow++;
} //while
// If everything went OK except errors in rows use DB_S_ERRORSOCCURRED.
return cErrors ? ( cErrors < cRows ) ?
( DB_S_ERRORSOCCURRED ) : ( DB_E_ERRORSOCCURRED ) : ( S_OK );
}
// CImpIRowsetChange::InsetRow --------------------------------------------
//
// @mfunc Insert row into provider
//
// Returns: S_OK if data changed successfully
// E_FAIL if Catch all (NULL pData, etc.)
// E_INVALIDARG if pcErrors!=NULL and paErrors==NULL
// E_OUTOFMEMORY if output error array couldn't be allocated
// DB_E_BADACCESSORHANDLE if invalid accessor
//
STDMETHODIMP CImpIRowsetChange::InsertRow
(
HCHAPTER hChapter, //@parm IN | The Chapter handle.
HACCESSOR hAccessor,
void* pData,
HROW* phRow
)
{
DBORDINAL cCols;
DBCOUNTITEM cBind;
BYTE* pbProvRow;
HRESULT hr;
ULONG irow;
DBCOUNTITEM cBindings;
DBBINDING* pBinding;
DBCOUNTITEM cErrorCount;
DBTYPE dwSrcType;
DBTYPE dwDstType;
void* pSrc;
void* pDst;
ULONG dwSrcLength;
DBLENGTH* pdwDstLength;
DBLENGTH cbDstMaxLength;
DWORD dwSrcStatus;
DWORD* pdwDstStatus;
DWORD dwPart;
PCOLUMNDATA pColumnData;
PACCESSOR paccessor = NULL;
BYTE* rgbRowDataSave = NULL;
BOOL fCanHoldRows = FALSE;
DBPROPIDSET rgPropertyIDSets[1];
ULONG cPropertySets;
DBPROPSET* prgPropertySets;
DBPROPID rgPropId[1];
DBCOLUMNINFO * rgdbcolumninfo = NULL;
// Initialize values
if( phRow )
*phRow = NULL;
// Check the Accessor Handle
assert( m_pObj->m_pextbufferAccessor );
if( FAILED( m_pObj->m_pextbufferAccessor->GetItemOfExtBuffer(hAccessor, &paccessor)) )
return( DB_E_BADACCESSORHANDLE );
// Ensure a source of data.
assert( paccessor );
if( paccessor->cBindings && !pData )
return( E_INVALIDARG );
// Get the value of the DBPROP_CANHOLDROWS property
rgPropertyIDSets[0].guidPropertySet = DBPROPSET_ROWSET;
rgPropertyIDSets[0].rgPropertyIDs = rgPropId;
rgPropertyIDSets[0].cPropertyIDs = 1;
rgPropId[0] = DBPROP_CANHOLDROWS;
assert( m_pObj->m_pUtilProp );
m_pObj->m_pUtilProp->GetProperties(
PROPSET_ROWSET,
1,
rgPropertyIDSets,
&cPropertySets,
&prgPropertySets );
// Get the Prompt value
if( V_BOOL(&prgPropertySets->rgProperties->vValue) == VARIANT_TRUE )
fCanHoldRows = TRUE;
// Free the memory
SAFE_FREE(prgPropertySets[0].rgProperties);
SAFE_FREE(prgPropertySets);
// Are there any unreleased rows?
if( ((m_pObj->m_prowbitsIBuffer)->ArrayEmpty() != S_OK) && (!fCanHoldRows) )
return( DB_E_ROWSNOTRELEASED );
if( FAILED( hr = GetNextSlots( m_pObj->m_pIBuffer, 1, &irow )) )
return hr;
if( FAILED( m_pObj->Rebind((BYTE *) m_pObj->GetRowBuff( irow, TRUE ))) )
return( E_FAIL );
// Get the rowbuffer and set the new bookmark
pbProvRow = (BYTE *) (m_pObj->GetRowBuff( irow, TRUE ));
((PROWBUFF) pbProvRow)->ulRefCount++;
((PROWBUFF) pbProvRow)->pbBmk = /*(BYTE*)*/ m_pObj->m_pFileio->GetRowCnt()+1;
m_pObj->m_ulRowRefCount++;
cBindings = paccessor->cBindings;
pBinding = paccessor->rgBindings;
// NULL Accessor (set Status to NULL)
if( !cBindings )
{
for (cCols = 1; cCols <= m_pObj->m_cCols; cCols++)
{
pColumnData = m_pObj->m_pFileio->GetColumnData(cCols, (ROWBUFF *) pbProvRow);
pColumnData->dwStatus = DBSTATUS_S_ISNULL;
}
}
// Apply accessor to data.
rgdbcolumninfo = m_pObj->m_pFileio->GetColInfo();
for (cBind = 0, cErrorCount = 0; cBind < cBindings; cBind++)
{
cCols = pBinding[cBind].iOrdinal;
// make sure column number is in range
if( cCols < 1 || cCols > m_pObj->m_cCols )
return( DB_E_BADORDINAL );
pColumnData = m_pObj->m_pFileio->GetColumnData(cCols, (ROWBUFF *)pbProvRow);
dwSrcType = pBinding[cBind].wType;
pDst = &(pColumnData->bData);
pdwDstLength = &(pColumnData->uLength);
pdwDstStatus = &(pColumnData->dwStatus);
cbDstMaxLength = pBinding[cBind].cbMaxLen;
dwPart = pBinding[cBind].dwPart;
dwDstType = rgdbcolumninfo[cCols].wType;
// Get the Length
if( dwPart & DBPART_LENGTH )
dwSrcLength = *(ULONG *)((BYTE*)pData + pBinding[cBind].obLength);
else
dwSrcLength = 0;
// Get the Status
if( dwPart & DBPART_STATUS )
dwSrcStatus = *(ULONG *)((BYTE*)pData + pBinding[cBind].obStatus);
else
dwSrcStatus = DBSTATUS_S_OK;
// Check the Status for DBSTATUS_S_DEFAULT
if( dwSrcStatus == DBSTATUS_S_DEFAULT )
dwSrcStatus = DBSTATUS_S_ISNULL;
// Check the Status for DBSTATUS_S_IGNORE
if( dwSrcStatus == DBSTATUS_S_IGNORE ||
dwSrcStatus == DBSTATUS_S_ISNULL )
continue;
// Check the Status of the value being sent in
if( dwSrcStatus != DBSTATUS_S_OK )
{
*(ULONG *)((BYTE*)pData + pBinding[cBind].obStatus) = DBSTATUS_E_BADSTATUS;
cErrorCount++;
continue;
}
// Get the Value
if( (dwPart & DBPART_VALUE) == 0 )
{
if( dwPart & DBPART_STATUS )
*(ULONG *)((BYTE*)pData + pBinding[cBind].obStatus) = DBSTATUS_E_UNAVAILABLE;
cErrorCount++;
continue;
}
else
{
pSrc = (void *) ((BYTE*) pData + pBinding[cBind].obValue);
}
// Check to see if we have a DC
if( !g_pIDataConvert )
return( E_FAIL );
hr = g_pIDataConvert->DataConvert(
dwSrcType,
dwDstType,
dwSrcLength,
pdwDstLength,
pSrc,
pDst,
cbDstMaxLength,
dwSrcStatus,
pdwDstStatus,
pBinding[cBind].bPrecision, // bPrecision for conversion to DBNUMERIC
pBinding[cBind].bScale, // bScale for conversion to DBNUMERIC
(DBDATACONVERT_SETDATABEHAVIOR |
(!dwSrcLength ? DBDATACONVERT_LENGTHFROMNTS : 0)));
// fatal error
if( FAILED( hr ) )
return hr;
// rounding or truncation or can't coerce
if( hr != S_OK )
cErrorCount++;
}
// If all bindings are bad and not a NULL Accessor
if( !cBindings || cErrorCount < cBindings )
{
// Carry out the insert.
if( FAILED(m_pObj->m_pFileio->UpdateRow((DBBKMARK) ((PROWBUFF) pbProvRow)->pbBmk, pbProvRow, INSERT )) )
return( E_FAIL );
// Set the RowHandle
if( phRow )
*phRow = irow;
}
// If everything went OK except errors in rows use DB_S_ERRORSOCCURRED.
return cErrorCount ? ( cErrorCount < cBindings ) ?
( DB_S_ERRORSOCCURRED ) : ( DB_E_ERRORSOCCURRED ) : ( S_OK );
}