Exposing Metadata
Providers expose information about the columns of a rowset through IColumnsInfo. The information for each column is returned in a DBCOLUMNINFO structure. For more details on the information contained in the DBCOLUMNINFO structure, see IColumnsInfo::GetColumnInfo in the OLE DB Programmer's Reference. OLE DB also enables sophisticated providers to expose a richer set of metadata through IColumnsRowset; the sample provider does not implement this interface.
Exposing Metadata to Consumers
The GetColumnInfo method returns metadata that is most commonly used by consumers: column ID, column name, the ordinal number of the column in the rowset, the column's data type, and so on. This information helps the consumer determine the binding type.
The provider returns the information in an array of DBCOLUMNINFO structures, one DBCOLUMNINFO structure per column in the rowset. The order of the structures returned in the array is the order in which the columns appear in the rowset.
The source code for IColumnsInfo::GetColumnInfo follows; you can find the complete source code for IColumnsInfo in ColInfo.cpp.
// IColumnsInfo specific methods
// CImpIColumnsInfo::GetColumnInfo -------------------------------------------
//
// @mfunc Returns the column metadata needed by most consumers.
//
// @rdesc HRESULT
// @flag S_OK | The method succeeded
// @flag E_OUTOFMEMORY | Out of memory
// @flag E_INVALIDARG | pcColumns or prginfo or ppStringsbuffer was NULL
//
STDMETHODIMP CImpIColumnsInfo::GetColumnInfo
(
DBORDINAL* pcColumns, //@parm OUT | Number of columns in rowset
DBCOLUMNINFO** prgInfo, //@parm OUT | Array of DBCOLUMNINFO Structures
WCHAR** ppStringsBuffer //@parm OUT | Storage for all string values
)
{
HRESULT hr = S_OK;
DBORDINAL cCols = 0;
DBORDINAL cExtraCols = 0;
DBORDINAL cbHeapUsed = 0;
DBORDINAL cIter = 0;
BYTE * pbHeap = NULL;
WCHAR * pwstrBuffer = NULL;
DBCOLUMNINFO * rgdbcolinfo = NULL;
DBCOLUMNINFO * rgdbInternalcolinfo = NULL;
DBCOLUMNINFO * rgdbExtracolinfo = NULL;
CRowset * pCRowset = NULL;
CFileIO * pFileio = NULL;
//
// Asserts
//
assert(m_pObj);
//
// Check in-params and NULL out-params in case of error
//
if( pcColumns )
*pcColumns = 0;
if( prgInfo )
*prgInfo = NULL;
if( ppStringsBuffer )
*ppStringsBuffer = NULL;
if( !pcColumns || !prgInfo || !ppStringsBuffer )
return E_INVALIDARG;
//
// Get the Column Information off of the Command or Rowset
//
if( m_pObj->GetBaseObjectType() == BOT_COMMAND )
{
//
// Asserts
//
assert(((CCommand *) m_pObj)->m_pCSession);
assert(((CCommand *) m_pObj)->m_pCSession->m_pCDataSource);
//
// Check that a command has been set
//
if( !((CCommand *) m_pObj)->IsCommandSet() )
return DB_E_NOCOMMAND;
//
// Try to open the file...
//
hr = ((CCommand *) m_pObj)->m_pCSession->m_pCDataSource->OpenFile(
((CCommand *) m_pObj)->GetCommandText(), &pFileio);
if( FAILED(hr) )
return hr;
}
else
{
if( m_pObj->GetBaseObjectType() == BOT_ROWSET )
pFileio = ((CRowset *) m_pObj)->GetFileObj();
else
{
pFileio = ((CRow *) m_pObj)->GetFileObj();
cExtraCols = ((CRow *) m_pObj)->GetExtraColCount();
rgdbExtracolinfo = ((CRow *) m_pObj)->GetExtraColumnInfo();
}
}
//
// Get the column count and delete unneeded info
//
cCols = pFileio->GetColumnCnt();
pbHeap = pFileio->GetColNameHeap();
cbHeapUsed = pFileio->GetColNameHeapSize();
rgdbInternalcolinfo = pFileio->GetColInfo();
//
// Return the column information
//
SAFE_ALLOC(rgdbcolinfo, DBCOLUMNINFO, (cCols + cExtraCols) * sizeof(DBCOLUMNINFO));
SAFE_ALLOC(pwstrBuffer, WCHAR, cbHeapUsed);
// 64 bit TODO
memcpy(rgdbcolinfo, &(rgdbInternalcolinfo[1]), (ULONG)cCols*sizeof(DBCOLUMNINFO));
memcpy(rgdbcolinfo+cCols, rgdbExtracolinfo, (ULONG)cExtraCols*sizeof(DBCOLUMNINFO));
//
// Need to fix up column ordinals for extra columns
//
for (cIter=cCols; cIter < cCols+cExtraCols; cIter++)
rgdbcolinfo[cIter].iOrdinal = cIter+1;
//
// Copy the heap for column names.
//
if( cbHeapUsed )
{
ptrdiff_t dp;
// 64 bit TODO
memcpy(pwstrBuffer, pbHeap, (DBORDINAL)cbHeapUsed);
dp = (DBBYTEOFFSET)pwstrBuffer - (DBBYTEOFFSET)(pbHeap);
dp >>= 1;
// Loop through columns and adjust pointers to column names.
for (ULONG icol=0; icol < cCols; icol++)
{
if( rgdbcolinfo[icol].pwszName )
rgdbcolinfo[icol].pwszName += dp;
}
}
//
// Assign in the values
//
*pcColumns = cCols + cExtraCols;
*prgInfo = rgdbcolinfo;
*ppStringsBuffer = pwstrBuffer;
CLEANUP:
//
// Cleanup the File Information
//
if( m_pObj->GetBaseObjectType() == BOT_COMMAND )
SAFE_DELETE(pFileio);
if( FAILED(hr) )
{
SAFE_DELETE(rgdbcolinfo);
SAFE_DELETE(pwstrBuffer);
}
return hr;
}