Share via


Updating Rows

IRowsetChange enables consumers to change the values of columns in a row of data. If the consumer wants to change the data, it must first construct an accessor for the columns to be changed. IRowsetChange contains three methods: DeleteRows, InsertRow, and SetData. The sample provider does not implement the InsertRow method.

Setting the New Data Values

IRowsetChange::SetData sets new data values for columns in a row. SetData cannot be used to change values in a deleted row. When SetData updates a row, it overwrites the row data in the provider's data cache and in the underlying data source with at signs (@), causing the row to appear deleted. Then it appends the new row to the end of the file. Changes made through SetData are applied to the data source immediately. The source code for IRowsetChange::SetData follows; you can find the complete source code for IRowsetChange in RowChng.cpp.

// 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;
    DBLENGTH           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   = (DBBYTEOFFSET *) &(pColumnData->dwLength);
        pdwDstStatus   = &(pColumnData->dwStatus);
        cbDstMaxLength = pBinding[cBind].cbMaxLen;

        dwPart         = pBinding[cBind].dwPart;
        dwDstType      = rgdbcolumninfo[cCols].wType;

        // Get the Length
      if( dwPart & DBPART_LENGTH )
         dwSrcLength = *(DBLENGTH *)((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 );
}

See Also

Tasks

Writing an OLE DB Provider: An Introduction