ROWCHNG.CPP

//-------------------------------------------------------------------- 
// Microsoft OLE DB Sample Provider
// (C) Copyright 1994 - 1996 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
)
{
PACCESSOR paccessor;
ULONG icol, ibind;
BYTE* pbProvRow;
HRESULT hr;
ULONG cBindings;
DBBINDING* pBinding;
ULONG dwErrorCount;
DBTYPE dwSrcType;
DBTYPE dwDstType;
void* pSrc;
void* pDst;
ULONG dwSrcLength;
ULONG* pdwDstLength;
ULONG dwDstMaxLength;
DWORD dwSrcStatus;
DWORD* pdwDstStatus;
DWORD dwPart;
PCOLUMNDATA pColumnData;
BYTE b;

BYTE* rgbRowDataSave = NULL;

rgbRowDataSave = (BYTE *) malloc( m_pObj->m_cbRowSize );
if (NULL == rgbRowDataSave)
return ResultFromScode( E_OUTOFMEMORY );

if ( m_pObj->m_pextbufferAccessor == NULL
|| FAILED( m_pObj->m_pextbufferAccessor->GetItemOfExtBuffer((ULONG) hAccessor, &paccessor))
|| paccessor == NULL)
{
return ResultFromScode( DB_E_BADACCESSORHANDLE );
}

assert( paccessor );

cBindings = paccessor->cBindings;
pBinding = paccessor->rgBindings;

// Is row handle right?
if ((m_pObj->m_prowbitsIBuffer)->IsSlotSet((ULONG) hRow ) != S_OK)
return ResultFromScode( DB_E_BADROWHANDLE );

// Ensure a source of data.
if (pData == NULL)
return ResultFromScode( E_INVALIDARG );

pbProvRow = (BYTE *) (m_pObj->GetRowBuff((ULONG) hRow ));

// Save the row.
memcpy( rgbRowDataSave, pbProvRow, m_pObj->m_cbRowSize );


// Apply accessor to data.
for (ibind = 0, dwErrorCount = 0; ibind < cBindings; ibind++)
{
icol = pBinding[ibind].iOrdinal;
pColumnData = (COLUMNDATA *) (pbProvRow + m_pObj->m_rgdwDataOffsets[icol]);

dwDstType = m_pObj->m_rgdbcolinfo[icol].wType;
pDst = &(pColumnData->bData);
pdwDstLength = (ULONG *) & (pColumnData->dwLength);
pdwDstStatus = &(pColumnData->dwStatus);
dwDstMaxLength = m_pObj->m_rgdbcolinfo[icol].ulColumnSize;

dwPart = pBinding[ibind].dwPart;
dwSrcType = pBinding[ibind].wType;

if ((dwPart & DBPART_VALUE) == 0)
{
if (((dwPart & DBPART_STATUS)
&& (*(ULONG *) ((BYTE*) pData + pBinding[ibind].obStatus) & DBSTATUS_S_ISNULL))
|| ((dwPart & DBPART_LENGTH) && *(ULONG *) ((BYTE*) pData + pBinding[ibind].obLength) == 0))
{
pSrc = &b;
b = 0x00;
}
else
return ResultFromScode( E_FAIL );
}
else
{
pSrc = (void *) ((BYTE*) pData + pBinding[ibind].obValue);
}

dwSrcLength = (dwPart & DBPART_LENGTH) ? *(ULONG *) ((BYTE*) pData + pBinding[ibind].obLength) : 0;

dwSrcStatus = (dwPart & DBPART_STATUS) ? *(ULONG *) ((BYTE*) pData + pBinding[ibind].obStatus)
: DBSTATUS_S_OK;

hr = g_pIDataConvert->DataConvert(
dwSrcType,
dwDstType,
dwSrcLength,
pdwDstLength,
pSrc,
pDst,
dwDstMaxLength,
dwSrcStatus,
pdwDstStatus,
0,// bPrecision for conversion to DBNUMERIC
0,// bScale for conversion to DBNUMERIC
DBDATACONVERT_SETDATABEHAVIOR);
if (FAILED( hr ))
return hr; // fatal error
if (hr != S_OK)
dwErrorCount++; // rounding or truncation or can't coerce
}

// Carry out the update.
if (FAILED( m_pObj->m_pFileio->UpdateRow((ULONG) ((PROWBUFF) pbProvRow)->pbBmk, m_pObj->m_rgdwDataOffsets, pbProvRow )))
{
// Restore the row to its previous state */
memcpy( pbProvRow, rgbRowDataSave, m_pObj->m_cbRowSize );
return ResultFromScode( E_FAIL );
}

free( rgbRowDataSave );

// We report any lossy conversions with a special status.
// Note that DB_S_ERRORSOCCURED is a success, rather than failure.
return ResultFromScode( dwErrorCount ? DB_S_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
(
HCHAPTERhReserved,//@parm IN| Reserved for future use
ULONG cRows,//@parm IN| Number of rows to delete
const HROW rghRows[],//@parm IN| Array of handles to delete
DBROWSTATUSrgRowStatus[]//@parm OUT | Error information
)
{
ULONG ihRow = 0L;
ULONG cErrors = 0L;
ULONG cRowReleased = 0L;
BYTE* pbProvRow;

// If No Row handle, just return.
if (0 == cRows)
return ResultFromScode( S_OK );

// Check for Invalid Arguments
if ((1 >= cRows) && (NULL == rghRows))
return ResultFromScode( E_INVALIDARG );

// Process row handles
while (ihRow < cRows)
{
if (rgRowStatus)
rgRowStatus[ihRow] = DBROWSTATUS_S_OK;

// Is row handle valid
if (S_OK != (m_pObj->m_prowbitsIBuffer)->IsSlotSet((ULONG) rghRows[ihRow] ))
{
// Log Error
if (rgRowStatus)
rgRowStatus[ihRow]= DBROWSTATUS_E_INVALID;

cErrors++;
ihRow++;
continue;
}

// Get RowBuffer to look at which row this applies to
pbProvRow = (BYTE *) (m_pObj->GetRowBuff((ULONG) rghRows[ihRow] ));

// Has row already been deleted
// S_OK means deleted
if (S_OK == m_pObj->m_pFileio->IsDeleted((ULONG) ((PROWBUFF) pbProvRow)->pbBmk ))
{
if (rgRowStatus)
rgRowStatus[ihRow] = DBROWSTATUS_E_DELETED;
cErrors++;
ihRow++;
continue;
}

// Delete the Row,
if (S_OK != m_pObj->m_pFileio->DeleteRow((ULONG) ((PROWBUFF) pbProvRow)->pbBmk ))
{
// Some better decision as to what rowstatus to set could be done here..
if (rgRowStatus)
rgRowStatus[ihRow] = DBROWSTATUS_E_PERMISSIONDENIED;
cErrors++;
ihRow++;
continue;
}
} //while


// If everything went OK except errors in rows use DB_S_ERRORSOCCURRED.
return cErrors ? (cErrors < cRows) ?
ResultFromScode(DB_S_ERRORSOCCURRED) :
ResultFromScode(DB_E_ERRORSOCCURRED) :
ResultFromScode(S_OK);
}

// CImpIRowsetChange::InsetRow --------------------------------------------
//
// @mfunc Insert row into provider
//
// @rdesc HRESULT
// @flag E_NOTSUPPORTED| this method is not implemented
//
STDMETHODIMP CImpIRowsetChange::InsertRow
(
HCHAPTERhReserved,
HACCESSORhAccessor,
void*pData,
HROW*phRow
)
{
return ResultFromScode( DB_E_NOTSUPPORTED );
}