Note
Access to this page requires authorization. You can try signing in or changing directories.
Access to this page requires authorization. You can try changing directories.
The session contains the interface that enables consumers to open a data file and create a rowset object containing all rows in the data file. The sample provider implements IOpenRowset on the session to create this rowset. The following section describes this interface.
Instantiating and Exposing a Rowset
The IOpenRowset interface contains a single method: OpenRowset. IOpenRowset is a required interface on the session. IOpenRowset::OpenRowset can be used by providers that do not support command objects to generate a rowset of all rows in a table or index. This provides a way for consumers to open and manipulate individual tables or indexes in a database with relatively low resource overhead. In the sample provider implementation, IOpenRowset accepts a file name as the name of the table and concatenates that with the directory name provided through IDBProperties::SetProperties. IOpenRowset uses the directory name and file name to instantiate a rowset and expose the rowset to the consumer.
The source code for the IOpenRowset::OpenRowset method follows; you can find the complete source code for the IOpenRowset interface in OpnRowst.cpp.
// CImpIOpenRowset::OpenRowset ------------------------------------------------
//
// @mfunc Opens and returns a rowset that includes all rows from a single base table
//
// @rdesc HRESULT
// @flag S_OK | The method succeeded
// @flag E_INVALIDARG | pTableID was NULL
// @flag E_FAIL | Provider-specific error
// @flag DB_E_NOTABLE | Specified table does not exist in current Data
// | Data Source object
// @flag E_OUTOFMEMORY | Out of memory
// @flag E_NOINTERFACE | The requested interface was not available
STDMETHODIMP CImpIOpenRowset::OpenRowset
(
IUnknown* pUnkOuter, //@parm IN | Controlling unknown, if any
DBID* pTableID, //@parm IN | table to open
DBID* pIndexID, //@parm IN | DBID of the index
REFIID riid, //@parm IN | interface to return
ULONG cPropertySets, //@parm IN | count of properties
DBPROPSET rgPropertySets[], //@parm INOUT | array of property values
IUnknown** ppRowset //@parm OUT | where to return interface
)
{
CCommand* pCCommand = NULL;
ICommandText* pICmdText = NULL;
ICommandProperties* pICmdProp = NULL;
CRowset* pRowset = NULL;
HRESULT hr;
HRESULT hrProp = ResultFromScode( S_OK );
ULONG ul,ul2;
assert( m_pObj );
assert( m_pObj->m_pUtilProp );
// NULL out-params in case of error
if( ppRowset )
*ppRowset = NULL;
// Check Arguments
if ( !pTableID && !pIndexID )
return ResultFromScode( E_INVALIDARG );
if ( riid == IID_NULL)
return ResultFromScode( E_NOINTERFACE );
// Check Arguments for use by properties
if( cPropertySets )
{
hr = m_pObj->m_pUtilProp->SetPropertiesArgChk(cPropertySets,
rgPropertySets);
if( FAILED(hr) )
return hr;
}
// We only accept NULL for pIndexID
if( pIndexID )
return ResultFromScode( DB_E_NOINDEX );
// If the eKind is not known to use, basically it
// means we have no table identifier
if ( (!pTableID ) || ( pTableID->eKind != DBKIND_NAME ) ||
( (pTableID->eKind == DBKIND_NAME) && (!(pTableID->uName.pwszName)) ) ||
( wcslen(pTableID->uName.pwszName) == 0 ) ||
( wcslen(pTableID->uName.pwszName) > _MAX_FNAME ) )
return ResultFromScode( DB_E_NOTABLE );
// We do not allow the riid to be anything other than IID_IUnknown for aggregation
if ( (pUnkOuter) && (riid != IID_IUnknown) )
return ResultFromScode( DB_E_NOAGGREGATION );
// Create a Command Object
// This is the outer unknown from the user, for the new Command,
// not to be confused with the outer unknown of this DBSession object.
pCCommand = new CCommand(m_pObj, NULL);
if (pCCommand)
{
hr = pCCommand->FInit();
if( FAILED(hr) )
{
delete pCCommand; // clean up.
pCCommand = NULL;
}
}
else
{
// Since Ctor failed, it cannot know to Release pUnkOuter,
// so we must do it here since we are owner.
if (pUnkOuter)
pUnkOuter->Release();
hr = E_OUTOFMEMORY;
}
if( pCCommand )
{
// Since we are using the command objects interfaces to impersonate
// doing IOpenRowset, we need to tell the command object to post errors
// as IID_IOpenRowset
pCCommand->SetImpersonateIID(&IID_IOpenRowset);
// Allocate buffer for Table Name.
if( FAILED(hr = pCCommand->QueryInterface(IID_ICommandText, (LPVOID*)&pICmdText)) )
{
assert(!"QI for ICmdText failed");
goto EXIT;
}
assert( pICmdText );
if( FAILED(hr = pICmdText->SetCommandText(DBGUID_DEFAULT, pTableID->uName.pwszName)) )
{
// Process Errors
goto EXIT;
}
// Process Properties
if( cPropertySets > 0 )
{
if( FAILED(hr = pCCommand->QueryInterface(IID_ICommandProperties, (LPVOID*)&pICmdProp)) )
{
assert(!"QI for ICmdProp failed");
goto EXIT;
}
assert( pICmdProp );
hr = (pICmdProp->SetProperties(cPropertySets, rgPropertySets));
if( (hr == DB_E_ERRORSOCCURRED) ||
(hr == DB_S_ERRORSOCCURRED) )
{
// If all the properties set were SETIFCHEAP then we can set
// our status to DB_S_ERRORSOCCURRED and continue.
for(ul=0;ul<cPropertySets; ul++)
{
for(ul2=0;ul2<rgPropertySets[ul].cProperties; ul2++)
{
// Check for a required property that failed, if found, we must return
// DB_E_ERRORSOCCURRED
if( (rgPropertySets[ul].rgProperties[ul2].dwStatus != DBPROPSTATUS_OK) &&
(rgPropertySets[ul].rgProperties[ul2].dwOptions != DBPROPOPTIONS_SETIFCHEAP) )
{
hr = ResultFromScode(DB_E_ERRORSOCCURRED);
goto EXIT;
}
}
}
hrProp = DB_S_ERRORSOCCURRED;
}
else if( FAILED(hr) )
{
goto EXIT;
}
}
// Open the rowset using ::Execute
// ppRowset buffer.
if( ppRowset )
{
hr = pICmdText->Execute(pUnkOuter, riid, NULL, NULL, ppRowset);
// Sample Provider's property handling is simplistic.
// All property errors should have been caught by the previous
// call to ::SetProperties.
// Assume that a failure was caused by something other
// than bad properties.
// So, no need for property post-processing
}
}
EXIT:
if( pICmdText )
pICmdText->Release();
if( pICmdProp )
pICmdProp->Release();
// DB_S_ERRORSOCCURRED must take precedence over DB_S_NOTSINGLETON
return (hr == S_OK || hr == DB_S_NOTSINGLETON) ? hrProp : hr;
}