Index Example

The following code accesses the Employees table through the Emp_LastName_Index index, using IRowsetIndex for the index and IRowsetLocate for the table.

The index has two columns. The first column, Emp_LastName, is of type DBTYPE_WSTR with a length of 30 characters and is the key column. The second column is of type DBTYPE_BYTES with a length of 4 characters and contains the bookmark for the Employees table. In the information returned by IColumnsInfo::GetColumnInfo for this column, the DBCOLUMNFLAGS_ISBOOKMARK is set.

The code sample performs the following actions:

  1. Initializes the database and creates a session (not shown).

  2. Obtains interfaces for the table and index. Only the latter is shown.

  3. Gets information about the column types of the index rowset (not shown).

  4. Establishes bindings for the table and index columns. Only the latter is shown.

  5. Creates accessors for the table and index rowsets. Only the latter is shown.

  6. Reads the index rowset and retrieves the corresponding row from the table rowset.
#include<oledb.h>
#include<stddef.h>

GetTableRowsetLocate(IOpenRowset* , BSTR, IRowsetLocate**);
PrintData(OLECHAR*, ULONG, HROW*);
IMalloc * pMalloc;  // pMalloc is the default memory allocator
HRESULT hr;

int main() {
 IOpenRowset  *pIOpenRowset = NULL;
 DBID    IndxId;
 IRowsetIndex *pIndex = NULL;
 IRowset    *pIndexRows = NULL;
 IRowsetLocate  *pIRSLocate =NULL;
 ULONG    *pColumns = NULL;
 DBCOLUMNINFO  **prgInfo;
 OLECHAR   **ppStringsBuffer;
 IColumnsInfo *pIndxColsInfo = NULL;
 IAccessor  *pIndxAccsr = NULL;
 HACCESSOR   hIndexAccBmk = DB_INVALID_HACCESSOR;

 // Initialize the database, create a session, and obtain, from the session object, a
 // pointer pIOpenRowset to an IOpenRowset interface. Code not shown.

 // Use IOpenRowset::OpenRowset to obtain a pointer to IRowsetIndex.
 // Set the Index's DBID
 IndxId.eKind = DBKIND_NAME;
 IndxId.uName.pwszName = OLESTR("Emp_LastName_Index");

 // Open the Index with default properties and default interfaces. (IRowsetIndex,
 // IAccessor, IRowset, IColumnsInfo, IRowsetInfo).
 pIOpenRowset->OpenRowset(NULL, NULL, &IndxId, IID_IRowsetIndex, 0, NULL,
          (IUnknown**) &pIndex);

 // Get a rowset for the table using a helper function.
 GetTableRowsetLocate(pIOpenRowset, OLESTR("Employees"), &pIRSLocate);

 // Get an accessor for the index.
 pIndex->QueryInterface(IID_IAccessor, (void**) &pIndxAccsr);

 // Get a rowset for index traversal.
 pIndex->QueryInterface(IID_IRowset, (void**) &pIndexRows);

 // Get a pointer to IColumnsInfo on the index and get information about the columns
 // of the index.
 pIndex->QueryInterface(IID_IColumnsInfo, (void**) &pIndxColsInfo);
 pIndxColsInfo->GetColumnInfo(pColumns, prgInfo, ppStringsBuffer);

 // Explore the DBCOLUMNINFO structures. The structure not corresponding to column
 // 0 and with a flag DBCOLUMNFLAGS_ISBOOKMARK set is the bookmark to the base
 // table. Suppose that the IColumnsInfo says that there are two columns, that
 // column 1 (which corresponds to the key) contains a string, and that the base
 // table bookmark is in column 2 and that it needs 4 bytes. Code not shown.
 // Create index and table bindings and corresponding accessors.
 typedef struct tagBmk{
  OLECHAR * Name;
  ULONG   cBookmark;
  BYTE  vBookmark[4];
 } Bmk;

 DBBINDSTATUS rgStatus[2];
 static DBBINDING IndxBinds[2]= {
  {
   1,         // Ordinal of key column
   0,         // obValue
   0,         // No length
   0,         // No status
   NULL,        // No TypeInfo
   NULL,        // No Object
   NULL,        // No binding extensions 
   DBPART_VALUE,      // Bind value
   DBMEMOWNER_CLIENTOWNED,  // Client-owned memory
   DBPARAMIO_NOTPARAM,
   0,         // cbMaxLen ignored
   0,
   DBTYPE_WSTR | DBTYPE_BYREF, // DBTYPE
   0,         // No Scale
   0          // No Precision
  },
  {
   2,          // Ordinal of base table bookmark
   offsetof(Bmk, vBookmark),   // Offset to value
   offsetof(Bmk,cBookmark),  // Offset to length
   0,          // No status
   NULL,         // No Type Info
   NULL,         // No object
   NULL,         // No binding extensions
   DBPART_VALUE | DBPART_LENGTH, // Bind value and length
   DBMEMOWNER_CLIENTOWNED,   // Client-owned memory
   DBPARAMIO_NOTPARAM,
   4,          // max length
   0,
   DBTYPE_BYTES,       // DBTYPE
   0,          // No Scale
   0           // No Precision
  }
 };

 pIndxAccsr->CreateAccessor(DBACCESSOR_ROWDATA, 2, IndxBinds, 0, &hIndexAccBmk,
          rgStatus);
 //...

 // Set a range Emp_LastName LIKE "Smith*". Notice that only the Name element of the
 // Bmk structure is used.
 Bmk Bookmark;
 Bookmark.Name = OLESTR("Smith");
 pIndex->SetRange(hIndexAccBmk, 1, &Bmk, 0, NULL, DBRANGE_PREFIX);
 pIndex->Seek(hIndexAccBmk, 1, &Bmk, DBSEEK_GE);

 // Traverse index within the range. For each matching index entry, retrieve the
 // corresponding record in the Employees table.
 ULONG    cIdxRows = 0, cTabRows = 0;
 HROW    *phIdxRows = NULL, *phTabRows = NULL;
 DBROWSTATUS  rgRowStatus[1];

 while(SUCCEEDED(hr = pIndexRows->GetNextRows(0, 0, 1, &cIdxRows, &phIdxRows)) &&
   cIdxRows > 0) {
  // Extract the bookmark from the index and read the table directly.
  pIndexRows->GetData(*phIdxRows, hIndexAccBmk, &Bookmark);
  pIRSLocate->GetRowsAt(0, NULL, Bookmark.cBookmark, &(Bookmark.vBookmark[0]), 0,
          1, &cTabRows, &phTabRows);
  PrintData(Bookmark.Name, cTabRows, phTabRows);

  // Release memory
  pMalloc->Free(Bookmark.Name);

  // Release the index and table rows 
  pIndexRows->ReleaseRows(cIdxRows, phIdxRows, NULL, rgRowStatus, rgRowOptions);
  pIRSLocate->ReleaseRows(cTabRows, phTabRows, NULL, rgRowStatus, rgRowOptions);
 };

 //Release the accessor
pIndxAccsr->ReleaseAccessor(hIndexAccBmk);

 //...
};