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

501 lines
16 KiB
C++

//--------------------------------------------------------------------
// Microsoft OLE DB Sample Provider
// (C) Copyright 1991-1999 Microsoft Corporation. All Rights Reserved.
//
// @doc
//
// @module ACCESSOR.CPP | CImpIAccessor object implementation
//
//
//
// Includes ------------------------------------------------------------------
#include "headers.h"
// Code ----------------------------------------------------------------------
// CImpIAccessor::FInit--------------------------------------------------------------
//
// @mfunc Initialize the Accessor implementation object.
//
// @rdesc Did the Initialization Succeed
// @flag S_OK | initialization succeeded,
// @flag E_OUTOFMEMORY | initialization failed because of memory allocation problem,
//-----------------------------------------------------------------------------------
STDMETHODIMP CImpIAccessor::FInit
(
BOOL fUnderRowset //@parm IN | Is aggregated within Rowset?
)
{
// Create the Extended Buffer array.
// This is an array of pointers to malloc'd accessors.
m_pextbufferAccessor = (LPEXTBUFFER) new CExtBuffer;
if (m_pextbufferAccessor == NULL || FAILED( m_pextbufferAccessor->FInit( 1, sizeof( PACCESSOR ), g_dwPageSize )))
return ResultFromScode( E_OUTOFMEMORY );
// If aggregated under Rowset do the following:
if(fUnderRowset)
{
// For efficiency reasons put a copy of the accessors buffer
// directly on the CRowset object.
((CRowset *)m_pObj)->m_pextbufferAccessor = m_pextbufferAccessor;
HRESULT hr;
CCommand *pCCommand;
CImpIAccessor *pIAccessorCommand;
// See if there are any accessors created on the Command object, and if so
// copy their handles so they can be used on the Rowset.
pCCommand = ((CRowset *)m_pObj)->m_pCreator;
if(pCCommand)
{
if(SUCCEEDED(pCCommand->QueryInterface(IID_IAccessor, (void **)&pIAccessorCommand)) && pIAccessorCommand)
{
// Copy handles.
hr = pIAccessorCommand->CopyAccessors(m_pextbufferAccessor);
pIAccessorCommand->Release();
if(FAILED(hr))
return hr;
}
}
}
return NOERROR;
}
// 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
(
HACCESSOR hAccessor, //@parm IN | Accessor Handle
DBREFCOUNT* 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;
if( pcRefCounts )
*pcRefCounts = 0;
m_pextbufferAccessor->GetItemOfExtBuffer(hAccessor, &pAccessor);
if( !pAccessor )
return DB_E_BADACCESSORHANDLE;
InterlockedIncrement((LONG*)&(pAccessor->cRef));
if( pcRefCounts )
*pcRefCounts = (DBREFCOUNT)(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.
//
// @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,
DBCOUNTITEM cBindings, //@parm IN | Number of Bindings
const DBBINDING rgBindings[], //@parm IN | Array of DBBINDINGS
DBLENGTH cbRowSize, //@parm IN | Number of bytes in consumer's buffer
HACCESSOR* phAccessor, //@parm OUT | Accessor Handle
DBBINDSTATUS rgStatus[] //@parm OUT | Binding status
)
{
PACCESSOR pAccessor;
HACCESSOR hAccessor;
DBCOUNTITEM cBind;
DBORDINAL cCols;
HRESULT hr;
// Check Parameters
if( (cBindings && !rgBindings) || (phAccessor == NULL) )
return ResultFromScode( E_INVALIDARG );
// init out params
*phAccessor = NULL;
// Check if we have a correct accessor type
if ( dwAccessorFlags & DBACCESSOR_PASSBYREF )
return ResultFromScode( DB_E_BYREFACCESSORNOTSUPPORTED );
// Only allow DBACCESSOR_ROWDATA and DBACCESSOR_OPTIMIZED
if ( (dwAccessorFlags & ~DBACCESSOR_OPTIMIZED ) != DBACCESSOR_ROWDATA )
return ResultFromScode( DB_E_BADACCESSORFLAGS );
// Check for NULL Accessor on the Command Object
// Also check for NULL Accessor on a read only rowset
if( (m_pObj->GetBaseObjectType() == BOT_COMMAND && !cBindings) ||
(m_pObj->GetBaseObjectType() == BOT_ROWSET && !cBindings && !((CRowset *)m_pObj)->SupportIRowsetChange()) )
return ResultFromScode( DB_E_NULLACCESSORNOTSUPPORTED );
// Check for Optimized Accessor on the Rowset Object after Fetch
if( (dwAccessorFlags & DBACCESSOR_OPTIMIZED) &&
m_pObj->GetBaseObjectType() == BOT_ROWSET && ((CRowset *)m_pObj)->m_cRows )
return ResultFromScode( DB_E_BADACCESSORFLAGS );
// Initialize the status array to DBBINDSTATUS_OK.
if ( rgStatus )
memset(rgStatus, 0x00, cBindings * sizeof(DBBINDSTATUS));
// Check on the bindings the user gave us.
for (cBind=0, hr=NOERROR; cBind < cBindings; cBind++)
{
// other binding problems forbidden by OLE-DB
const DBTYPE currType = rgBindings[cBind].wType;
const DBTYPE currTypePtr = currType &
(DBTYPE_BYREF|DBTYPE_ARRAY|DBTYPE_VECTOR);
const DBTYPE currTypeBase = currType &
~(DBTYPE_BYREF|DBTYPE_ARRAY|DBTYPE_VECTOR);
const DWORD currFlags = rgBindings[cBind].dwFlags;
cCols = rgBindings[cBind].iOrdinal;
// Check for a Bad Ordinal
if( m_pObj->GetBaseObjectType() == BOT_ROWSET )
{
// make sure column number is in range
if ( !(0 < cCols && cCols <= ((CRowset *) m_pObj)->m_cCols) )
{
// Set Bind status to DBBINDSTATUS_BADORDINAL
hr = ResultFromScode( DB_E_ERRORSOCCURRED );
if ( rgStatus )
rgStatus[cBind] = DBBINDSTATUS_BADORDINAL;
continue;
}
}
// At least one of these valid parts has to be set. In SetData I assume it is the case.
if ( !(rgBindings[cBind].dwPart & (DBPART_VALUE|DBPART_LENGTH|DBPART_STATUS)) )
{
// Set Bind status to DBBINDSTATUS_BADBINDINFO
hr = ResultFromScode( DB_E_ERRORSOCCURRED );
if ( rgStatus )
rgStatus[cBind] = DBBINDSTATUS_BADBINDINFO;
}
// dwPart is something other than value, length, or status
else if ( (rgBindings[cBind].dwPart & ~(DBPART_VALUE|DBPART_LENGTH|DBPART_STATUS)) )
{
// Set Bind status to DBBINDSTATUS_BADBINDINFO
hr = ResultFromScode( DB_E_ERRORSOCCURRED );
if ( rgStatus )
rgStatus[cBind] = DBBINDSTATUS_BADBINDINFO;
}
// wType was DBTYPE_EMPTY or DBTYPE_NULL
else if ( (currType==DBTYPE_EMPTY || currType==DBTYPE_NULL) )
{
// Set Bind status to DBBINDSTATUS_BADBINDINFO
hr = ResultFromScode( DB_E_ERRORSOCCURRED );
if ( rgStatus )
rgStatus[cBind] = DBBINDSTATUS_BADBINDINFO;
}
// wType was DBTYPE_BYREF or'ed with DBTYPE_EMPTY, NULL, or RESERVED
else if ( ((currType & DBTYPE_BYREF) &&
(currTypeBase == DBTYPE_EMPTY || currTypeBase == DBTYPE_NULL ||
currType & DBTYPE_RESERVED)) )
{
// Set Bind status to DBBINDSTATUS_BADBINDINFO
hr = ResultFromScode( DB_E_ERRORSOCCURRED );
if ( rgStatus )
rgStatus[cBind] = DBBINDSTATUS_BADBINDINFO;
}
// dwFlags was DBBINDFLAG_HTML and the type was not a String
else if ( currFlags && (currFlags != DBBINDFLAG_HTML ||
(currTypeBase != DBTYPE_STR &&
currTypeBase != DBTYPE_WSTR &&
currTypeBase != DBTYPE_BSTR)) )
{
// Set Bind status to DBBINDSTATUS_BADBINDINFO
hr = ResultFromScode( DB_E_ERRORSOCCURRED );
if ( rgStatus )
rgStatus[cBind] = DBBINDSTATUS_BADBINDINFO;
}
// wType was used with more than one type indicators
else if ( !(currTypePtr == 0 || currTypePtr == DBTYPE_BYREF ||
currTypePtr == DBTYPE_ARRAY || currTypePtr == DBTYPE_VECTOR) )
{
// Set Bind status to DBBINDSTATUS_BADBINDINFO
hr = ResultFromScode( DB_E_ERRORSOCCURRED );
if ( rgStatus )
rgStatus[cBind] = DBBINDSTATUS_BADBINDINFO;
}
// wType was a non pointer type with provider owned memory
else if ( !currTypePtr &&
rgBindings[cBind].dwMemOwner==DBMEMOWNER_PROVIDEROWNED )
{
// Set Bind status to DBBINDSTATUS_BADBINDINFO
hr = ResultFromScode( DB_E_ERRORSOCCURRED );
if ( rgStatus )
rgStatus[cBind] = DBBINDSTATUS_BADBINDINFO;
}
// we only support client owned memory
else if ( rgBindings[cBind].dwMemOwner != DBMEMOWNER_CLIENTOWNED )
{
// Set Bind status to DBBINDSTATUS_BADBINDINFO
hr = ResultFromScode( DB_E_ERRORSOCCURRED );
if ( rgStatus )
rgStatus[cBind] = DBBINDSTATUS_BADBINDINFO;
}
}
// Any errors amongst those checks?
if (hr != NOERROR)
{
return hr;
}
// Make a copy of the client's binding array, and the type of binding.
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_pextbufferAccessor );
hr = m_pextbufferAccessor->InsertIntoExtBuffer(&pAccessor, hAccessor);
if ( FAILED( hr ) )
{
SAFE_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;
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
DBCOUNTITEM* 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;
DBCOUNTITEM cBindingSize;
// init out-params
if( pdwAccessorFlags )
*pdwAccessorFlags = 0;
if( pcBindings )
*pcBindings = 0;
if ( prgBindings )
*prgBindings = NULL;
// check parameters
if (!pdwAccessorFlags || !pcBindings || !prgBindings)
return ResultFromScode( E_INVALIDARG );
// Validate Accessor Handle
m_pextbufferAccessor->GetItemOfExtBuffer(hAccessor, &pAccessor);
if( !pAccessor )
return DB_E_BADACCESSORHANDLE;
// Allocate and return Array of bindings
cBindingSize = pAccessor->cBindings * sizeof( DBBINDING );
if ( cBindingSize )
*prgBindings = (DBBINDING *) PROVIDER_ALLOC( cBindingSize );
// Check the Allocation
if ( ( *prgBindings == NULL ) && ( cBindingSize ) )
return ResultFromScode( E_OUTOFMEMORY );
*pdwAccessorFlags = pAccessor->dwAccessorFlags;
*pcBindings = pAccessor->cBindings;
memcpy( *prgBindings, pAccessor->rgBindings, cBindingSize );
// 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
(
HACCESSOR hAccessor, //@parm IN | Accessor handle to release
DBREFCOUNT* 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;
if( pcRefCounts )
*pcRefCounts = 0;
m_pextbufferAccessor->GetItemOfExtBuffer(hAccessor, &pAccessor);
if( !pAccessor )
return DB_E_BADACCESSORHANDLE;
// Free the actual structure.
InterlockedDecrement((LONG*)&(pAccessor->cRef));
if( pAccessor->cRef <= 0 )
{
SAFE_DELETE( pAccessor );
if( pcRefCounts )
*pcRefCounts = 0;
// 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_pextbufferAccessor)[hAccessor]) = NULL;
}
else
{
if( pcRefCounts )
*pcRefCounts = (DBREFCOUNT)(pAccessor->cRef);
}
return ResultFromScode( S_OK );
}
// CImpIAccessor::CopyAccessors------------------------------------------------------
//
// @mfunc Copies accessors from one instantiation of the IAccessor to another (e.g.
// from one under ICommand to the one owned by IRowset implementation object).
//
// @rdesc Returns one of the following values:
// @flag S_OK | copying of the accessors succeeded,
// @flag E_OUTOFMEMORY | copying failed due to memory allocation
// failure for a new accessor,
// @flag OTHER | other result codes returned by called
// functions.
//-----------------------------------------------------------------------------------
STDMETHODIMP CImpIAccessor::CopyAccessors
(
LPEXTBUFFER pextbufferAccessor//@parm IN | specifies extended buffer
// to which accessors should be copied
)
{
HACCESSOR hAccessor, hAccessorFirst, hAccessorLast, hAccessorDup;
size_t cbAccessor;
PACCESSOR paccessor=NULL, paccessorNew=NULL, paccessorNull=NULL;
HRESULT hr;
assert(pextbufferAccessor);
if(pextbufferAccessor)
{
// Get the number of available accessors.
m_pextbufferAccessor->GetFirstLastItemH(hAccessorFirst, hAccessorLast);
for(hAccessor=hAccessorFirst; hAccessor <= hAccessorLast; hAccessor++)
{
hr = m_pextbufferAccessor->GetItemOfExtBuffer(hAccessor, &paccessor );
if( FAILED(hr) )
return hr;
if (paccessor == NULL)
paccessorNew = paccessorNull;
else
{
// Allocate space for the accessor structure.
cbAccessor = sizeof(ACCESSOR)
+ (paccessor->cBindings ?
(paccessor->cBindings-1) : 0)
* sizeof(DBBINDING);
paccessorNew = (PACCESSOR) new BYTE [cbAccessor];
if (paccessorNew == NULL)
return ResultFromScode(E_OUTOFMEMORY);
memcpy( paccessorNew, paccessor, cbAccessor);
paccessorNew->cRef = 1;
}
// Insert accessor ptr into the new buffer.
hr = pextbufferAccessor->InsertIntoExtBuffer(&paccessorNew, hAccessorDup);
// Can fail because of Out-Of-Memory condition.
if(FAILED(hr))
{
SAFE_DELETE(paccessorNew);
return hr;
}
}
}
return NOERROR;
}