Share via


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;
}

See Also

Tasks

Writing an OLE DB Provider: An Introduction