ACCESSOR.CPP

//-------------------------------------------------------------------- 
// Microsoft OLE DB Sample Provider
// (C) Copyright 1994 - 1996 Microsoft Corporation. All Rights Reserved.
//
// @doc
//
// @module ACCESSOR.CPP | CImpIAccessor object implementation
//
//
//

// Includes ------------------------------------------------------------------

#include "headers.h"

// Code ----------------------------------------------------------------------

// IAccessor specific methods

// CImpIAccessor::AddRefAccessor -----------------------------------------
//
// @mfunc Adds a reference count to an existing accessor
//
// @rdesc HRESULT
// @flag S_OK | Method Succeeded
// @flag E_FAIL | Provider specific Error
//
STDMETHODIMP CImpIAccessor::AddRefAccessor
(
HACCESSORhAccessor,//@parm IN | Accessor Handle
ULONG*pcRefCounts//@parm OUT | Reference Count
)
{
// Retrieve our accessor structure from the client's hAccessor,
// free it, then mark accessor ptr as unused.
// We do not re-use accessor handles. This way, we hope
// to catch more client errors. (Also, ExtBuffer doesn't
// maintain a free list, so it doesn't know how to.)

PACCESSOR pAccessor;
HRESULT hr;

if( pcRefCounts )
*pcRefCounts = 0;

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

InterlockedIncrement(&(pAccessor->cRef));

if( pcRefCounts )
*pcRefCounts = (ULONG)(pAccessor->cRef);

return ResultFromScode(S_OK);
}


// CImpIAccessor::CreateAccessor -----------------------------------------
//
// @mfunc Creates a set of bindings that can be used to send data
// to or retrieve data from the data cache.
// NOTE: Currently does not support returning rgStatus[].
//
// @rdesc HRESULT
// @flag S_OK | Method Succeeded
// @flag E_FAIL | Provider specific Error
// @flag E_INVALIDARG | pHAccessor was NULL, dwAccessorFlags was
// invalid, or cBindings was not 0 and
// rgBindings was NULL
// @flag E_OUTOFMEMORY | Out of Memory
// @flag DB_E_ERRORSOCCURRED| dwBindPart in an rgBindings element was invalid, OR
// | Column number specified was out of range, OR
//| Requested coercion is not supported.
// @flag OTHER | Other HRESULTs returned by called functions
//
STDMETHODIMP CImpIAccessor::CreateAccessor
(
DBACCESSORFLAGS dwAccessorFlags,
ULONG cBindings, //@parm IN | Number of Bindings
const DBBINDING rgBindings[], //@parm IN | Array of DBBINDINGS
ULONG cbRowSize, //@parm IN | Number of bytes in consumer's buffer
HACCESSOR* phAccessor, //@parm OUT | Accessor Handle
DBBINDSTATUSrgStatus[]//@parm OUT| Binding status
)
{
PACCESSOR pAccessor;
ULONG hAccessor;
ULONG ibind;
ULONG icol;
HRESULT hr;


// Check Parameters
if( (cBindings && !rgBindings) ||
(phAccessor == NULL) )
return ResultFromScode( E_INVALIDARG );

// init out params
*phAccessor = (HACCESSOR) 0;


// Check for the binding types we don't accept..
if ((dwAccessorFlags & DBACCESSOR_PASSBYREF) ||
(dwAccessorFlags & DBACCESSOR_PARAMETERDATA))
return ResultFromScode( E_INVALIDARG );

// .. then check for the binding type that is required
if (!(dwAccessorFlags & DBACCESSOR_ROWDATA))
return ResultFromScode( E_INVALIDARG );


// Check on the bindings the user gave us.
for (ibind =0, hr =NOERROR; ibind < cBindings; ibind++)
{
icol = rgBindings[ibind].iOrdinal;

// make sure column number is in range
if (!(0 < icol && icol <= m_pObj->m_cCols))
{
TRACE( "CreateAccessor failure: binding %d, bad column number %d\n", ibind, icol );
hr = ResultFromScode( DB_E_ERRORSOCCURRED );
break;
}

// At least one of these valid parts has to be set. In SetData I assume it is the case.
if ((rgBindings[ibind].dwPart & DBPART_VALUE) == 0
&& (rgBindings[ibind].dwPart & DBPART_LENGTH) == 0
&& (rgBindings[ibind].dwPart & DBPART_STATUS) == 0)
{
TRACE( "CreateAccessor failure: binding %d, column %d, _VALUE, _LENGTH, _STATUS not specified", ibind, icol );
hr = ResultFromScode( DB_E_ERRORSOCCURRED );

if ( rgStatus )
{
// Set Bind status to DBBINDSTATUS_BADBINDINFO
}
break;
}

// Make sure we can do the coercion that is requested
if( NOERROR != g_pIDataConvert->CanConvert(rgBindings[ibind].wType, m_pObj->m_rgdbcolinfo[icol].wType) ||
NOERROR != g_pIDataConvert->CanConvert(m_pObj->m_rgdbcolinfo[icol].wType, rgBindings[ibind].wType) )
{
TRACE( "CreateAccessor failure: binding %d, column %d, cannot coerce types\n", ibind, icol );
hr = ResultFromScode( DB_E_ERRORSOCCURRED );
if ( rgStatus )
{
// Set Bind status to DBBINDSTATUS_UNSUPPORTEDCONVERSION
}
break;
}
}

// Any errors amongst those checks?
if (hr != NOERROR)
{
return hr;
}

// Make a copy of the client's binding array, and the type of binding.
// Note: accessors with no bindings (cBindings=0) are legal.
pAccessor = (ACCESSOR *) new BYTE[sizeof( ACCESSOR ) + (cBindings - 1) *sizeof( DBBINDING )];
if (pAccessor == NULL)
return ResultFromScode( E_OUTOFMEMORY );

// We store a ptr to the newly created variable-sized ACCESSOR.
// We have an array of ptrs (to ACCESSOR's).
// The handle is the index into the array of ptrs.
// The InsertIntoExtBuffer function appends to the end of the array.
assert( m_pObj->m_pextbufferAccessor );
hr = m_pObj->m_pextbufferAccessor->InsertIntoExtBuffer( &pAccessor, hAccessor );
if (FAILED( hr ))
{
delete [] pAccessor;
return ResultFromScode( E_OUTOFMEMORY );
}
assert( hAccessor );

// Copy the client's bindings into the ACCESSOR.
pAccessor->dwAccessorFlags= dwAccessorFlags;
pAccessor->cBindings= cBindings;
pAccessor->cRef= 1;// Establish Reference count.
memcpy( &(pAccessor->rgBindings[0]), &rgBindings[0], cBindings*sizeof( DBBINDING ));

// fill out-param and return
*phAccessor = (HACCESSOR) hAccessor;
return ResultFromScode( S_OK );
}


// CImpIAccessor::GetBindings --------------------------------------------------
//
// @mfunc Returns the bindings in an accessor
//
// @rdesc HRESULT
// @flag S_OK | Method Succeeded
// @flag E_INVALIDARG | pdwAccessorFlags/pcBinding/prgBinding were NULL
// @flag E_OUTOFMEMORY | Out of Memory
// @flag DB_E_BADACCESSORHANDLE | Invalid Accessor given
//
STDMETHODIMP CImpIAccessor::GetBindings
(
HACCESSOR hAccessor, //@parm IN | Accessor Handle
DBACCESSORFLAGS* pdwAccessorFlags, //@parm OUT | Binding Type flag
ULONG* pcBindings, //@parm OUT | Number of Bindings returned
DBBINDING** prgBindings //@parm OUT | Bindings
)
{
// Retrieve our accessor structure from the client's hAccessor,
// make a copy of the bindings for the user, then done.
PACCESSOR pAccessor;
ULONG cBindingSize;
HRESULT hr;

// check parameters
if (!pdwAccessorFlags || !pcBindings || !prgBindings)
return ResultFromScode( E_INVALIDARG );

// init out-params
*pdwAccessorFlags = 0;
*pcBindings = 0;
*prgBindings = NULL;

// Validate Accessor Handle
hr = m_pObj->m_pextbufferAccessor->GetItemOfExtBuffer((ULONG) hAccessor, &pAccessor );
if (FAILED( hr ) || pAccessor == NULL)
return ResultFromScode( DB_E_BADACCESSORHANDLE );

// Allocate and return Array of bindings
cBindingSize = pAccessor->cBindings * sizeof( DBBINDING );
*prgBindings = (DBBINDING *) g_pIMalloc->Alloc( cBindingSize );
if (*prgBindings)
{
*pdwAccessorFlags = pAccessor->dwAccessorFlags;
*pcBindings = pAccessor->cBindings;
memcpy( *prgBindings, pAccessor->rgBindings, cBindingSize );
}
else
{
return ResultFromScode( E_OUTOFMEMORY );
}

// all went well..
return ResultFromScode( S_OK );
}



// CImpIAccessor::ReleaseAccessor ---------------------------------------
//
// @mfunc Releases an Accessor
//
// @rdesc HRESULT
// @flag S_OK | Method Succeeded
// @flag DB_E_BADACCESSORHANDLE | hAccessor was invalid
//
STDMETHODIMP CImpIAccessor::ReleaseAccessor
(
HACCESSORhAccessor, //@parm IN | Accessor handle to release
ULONG*pcRefCounts//@parm OUT | Reference Count
)
{
// Retrieve our accessor structure from the client's hAccessor,
// free it, then mark accessor ptr as unused.
// We do not re-use accessor handles. This way, we hope
// to catch more client errors. (Also, ExtBuffer doesn't
// maintain a free list, so it doesn't know how to.)

PACCESSOR pAccessor;
HRESULT hr;

if( pcRefCounts )
*pcRefCounts = 0;

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

// Free the actual structure.
InterlockedDecrement(&(pAccessor->cRef));
assert( pAccessor->cRef >= 0 );
if( pAccessor->cRef <= 0 )
{
delete [] pAccessor;
if( pcRefCounts )
*pcRefCounts = 0;
}
else
{
if( pcRefCounts )
*pcRefCounts = (ULONG)(pAccessor->cRef);
}

// Store a null in our array-of-ptrs,
// so we know next time that it is invalid.
// (operator[] returns a ptr to the space where the ptr is stored.)
*(PACCESSOR*) ((*m_pObj->m_pextbufferAccessor)[ (ULONG) hAccessor]) = NULL;

return ResultFromScode( S_OK );
}