How To

How to retrieve rows using bookmarks (OLE DB)

The consumer sets the dwFlag field value of the binding structure to DBCOLUMNSINFO_ISBOOKMARK to indicate that the column is used as bookmark. The consumer also sets the rowset property DBPROP_BOOKMARKS to VARIANT_TRUE. This allows column 0 to be present in the rowset.  IRowsetLocate::GetRowsAt is then used to fetch rows starting with the row specified an an offset from a bookmark.

To retrieve rows using bookmarks

  1. Establish a connection to the data source.

  2. Set the rowset property DBPROP_IRowsetLocate property to VARIANT_TRUE.

  3. Execute the command.

  4. Set the dwFlags field of the binding structure to DBCOLUMNSINFO_ISBOOKMARK flag for the column that will be used as a bookmark.

  5. Use IRowsetLocate::GetRowsAt to fetch rows, starting with the row specified by an offset from the bookmark.

The following example shows how to fetch rows using a bookmark. In this example, the5th row is retrieved from the result set produced from the execution of a SELECT statement.

/*
    How to use bookmarks
*/
void InitializeAndEstablishConnection();
void ProcessResultSet();

#define UNICODE
#define _UNICODE
#define DBINITCONSTANTS
#define INITGUID


#include <stdio.h>
#include <tchar.h>
#include <stddef.h>
#include <windows.h>
#include <iostream.h>
#include <oledb.h>
#include <sqloledb.h>

IDBInitialize*       pIDBInitialize     = NULL; 
IDBProperties*       pIDBProperties     = NULL;        
IDBCreateSession*    pIDBCreateSession  = NULL;
IDBCreateCommand*    pIDBCreateCommand  = NULL;
ICommandProperties*  pICommandProperties = NULL;
ICommandText*        pICommandText    = NULL;
IRowset*             pIRowset         = NULL;
IColumnsInfo*        pIColumnsInfo       = NULL;
DBCOLUMNINFO*        pDBColumnInfo      = NULL;
IAccessor*           pIAccessor         = NULL;
IRowsetLocate*       pIRowsetLocate      = NULL;

DBPROP               InitProperties[4];
DBPROPSET            rgInitPropSet[1]; 
DBPROPSET            rgPropSets[1];
DBPROP               rgProperties[1];
ULONG                i, j;              
HRESULT              hr;
LONG                 cNumRows = 0;
ULONG                lNumCols;
WCHAR*               pStringsBuffer;
DBBINDING*           pBindings;
ULONG                ConsumerBufferColOffset = 0;
HACCESSOR            hAccessor;
ULONG                lNumRowsRetrieved;
HROW                 hRows[5];         
HROW*                pRows = &hRows[0];
char*                pBuffer;

void main() {

    //The command to execute.
    WCHAR* wCmdString 
        = OLESTR(" SELECT title_id, title FROM titles ");

  // Initialize and establish a connection to the data source.
    InitializeAndEstablishConnection();

    //Create a session object.
    if(FAILED(pIDBInitialize->QueryInterface(
                                IID_IDBCreateSession,
                                (void**) &pIDBCreateSession)))
    {
        cout << "Failed to obtain IDBCreateSession interface.\n";
    }

    if(FAILED(pIDBCreateSession->CreateSession(
                                    NULL, 
                                    IID_IDBCreateCommand, 
                                    (IUnknown**) &pIDBCreateCommand)))
    {
        cout << "pIDBCreateSession->CreateSession failed.\n";
    }

    //Access the ICommandText interface.
    if(FAILED(pIDBCreateCommand->CreateCommand(
                                    NULL, 
                                    IID_ICommandText, 
                                    (IUnknown**) &pICommandText)))
    {
        cout << "Failed to access ICommand interface.\n";
    }

    //Set DBPROP_IRowsetLocate
    if(FAILED(pICommandText->QueryInterface( 
                                    IID_ICommandProperties, 
                                    (void **) &pICommandProperties )))
    {
        cout << "Failed to obtain ICommandProperties interface.\n";
    }

    /*
    Set DBPROP_IRowsetLocate to VARIANT_TRUE to 
    get the IRowsetLocate interface.
    */
    VariantInit(&rgProperties[0].vValue);

    rgPropSets[0].guidPropertySet   = DBPROPSET_ROWSET;
    rgPropSets[0].cProperties       = 1;
    rgPropSets[0].rgProperties      = rgProperties;

    //Set properties in the property group (DBPROPSET_ROWSET) 
    rgPropSets[0].rgProperties[0].dwPropertyID  = DBPROP_IRowsetLocate;
    rgPropSets[0].rgProperties[0].dwOptions     = DBPROPOPTIONS_REQUIRED;
    rgPropSets[0].rgProperties[0].colid         = DB_NULLID;
    rgPropSets[0].rgProperties[0].vValue.vt     = VT_BOOL;
    rgPropSets[0].rgProperties[0].vValue.boolVal = VARIANT_TRUE;

    //Set the rowset properties.
    hr = pICommandText->QueryInterface(
                                IID_ICommandProperties,
                                (void **)&pICommandProperties);
    if (FAILED(hr))
    {
        printf("Failed to get ICommandProperties to set rowset properties.\n");
        //Release any references and return.
    } //end if

    hr = pICommandProperties->SetProperties(1, rgPropSets);
    if (FAILED(hr))
    {
        printf("Execute failed to set rowset properties.\n");
        //Release any references and return.
    } //end if

    pICommandProperties->Release();

    //Specify the command text.
    if(FAILED(pICommandText->SetCommandText(
                                    DBGUID_DBSQL, 
                                    wCmdString)))
    {
        cout << "Failed to set command text.\n";
    }

    //Execute the command.
    if(FAILED(hr = pICommandText->Execute(
                                    NULL, 
                                    IID_IRowset, 
                                    NULL, 
                                    &cNumRows, 
                                    (IUnknown **) &pIRowset)))    
    {
        cout << "Failed to execute command.\n";
    }

    ProcessResultSet(); 
                        
    pIRowset->Release();

    //Free up memory.
    pICommandText->Release();
    pIDBCreateCommand->Release();
    pIDBCreateSession->Release();
    
    if(FAILED(pIDBInitialize->Uninitialize()))
    {
        /*
        Uninitialize is not required, but it fails if an interface
        has not been released.  This can be used for debugging.
        */
        cout << "Problem uninitializing.\n";
    } //if.
    pIDBInitialize->Release();
    
    //Release COM library.
    CoUninitialize();
};
//--------------------------------------------------------------------
void InitializeAndEstablishConnection()
{    
    //Initialize the COM library.
    CoInitialize(NULL);

    //Obtain access to the SQLOLEDB provider.
    CoCreateInstance(   CLSID_SQLOLEDB, 
                        NULL, CLSCTX_INPROC_SERVER,
                        IID_IDBInitialize, 
                        (void **) &pIDBInitialize);

    //Initialize the property values that are the same for each property.
    for(i = 0; i < 5; i++) {
        VariantInit(&InitProperties[i].vValue);
        InitProperties[i].dwOptions = DBPROPOPTIONS_REQUIRED;
        InitProperties[i].colid     = DB_NULLID;
    }

    //Server name.
    InitProperties[0].dwPropertyID = DBPROP_INIT_DATASOURCE;
    InitProperties[0].vValue.vt = VT_BSTR;
    InitProperties[0].vValue.bstrVal = 
                            SysAllocString((LPOLESTR)L"server");

    //Database.
    InitProperties[1].dwPropertyID = DBPROP_INIT_CATALOG;
    InitProperties[1].vValue.vt = VT_BSTR;
    InitProperties[1].vValue.bstrVal = SysAllocString((LPOLESTR)L"pubs");

    //Login.
    InitProperties[2].dwPropertyID = DBPROP_AUTH_USERID; 
    InitProperties[2].vValue.vt = VT_BSTR;
    InitProperties[2].vValue.bstrVal = SysAllocString((LPOLESTR)L"login");

    //Password.
    InitProperties[3].dwPropertyID = DBPROP_AUTH_PASSWORD;
    InitProperties[3].vValue.vt = VT_BSTR;
    InitProperties[3].vValue.bstrVal = SysAllocString((LPOLESTR)"password");

    //Construct the PropertySet array.
    rgInitPropSet[0].guidPropertySet = DBPROPSET_DBINIT;
    rgInitPropSet[0].cProperties = 4;
    rgInitPropSet[0].rgProperties = InitProperties;

    //Set initialization properties.
    pIDBInitialize->QueryInterface(IID_IDBProperties, 
                                    (void **)&pIDBProperties);

    hr = pIDBProperties->SetProperties(1, rgInitPropSet); 
    if(FAILED(hr))
    {
        cout << "Failed to set initialization properties.\n";
    }

    pIDBProperties->Release();

    //Call the initialization method to establish the connection.
    if(FAILED(pIDBInitialize->Initialize()))
    {
        cout << "Problem initializing and connecting to the data source.\n";
    }
} //end of InitializeAndEstablishConnection.
//-------------------------------------------------------------------
void ProcessResultSet()
{
    //Retrieve 5th row from the rowset (for example).
    int iBookmark = 5;

    pIRowset->QueryInterface(
                    IID_IColumnsInfo, 
                    (void **)&pIColumnsInfo);

    pIColumnsInfo->GetColumnInfo(
                        &lNumCols, 
                        &pDBColumnInfo, 
                        &pStringsBuffer);

    //Create a DBBINDING array.
    pBindings = new DBBINDING[lNumCols];

    //Using the ColumnInfo strucuture, fill out the pBindings array.
    for(j=0; j<lNumCols; j++) {
        pBindings[j].iOrdinal  = j;
        pBindings[j].obValue   = ConsumerBufferColOffset;
        pBindings[j].pTypeInfo = NULL;
        pBindings[j].pObject   = NULL;
        pBindings[j].pBindExt  = NULL;
        pBindings[j].dwPart    = DBPART_VALUE;
        pBindings[j].dwMemOwner = DBMEMOWNER_CLIENTOWNED;
        pBindings[j].eParamIO  = DBPARAMIO_NOTPARAM;
        pBindings[j].cbMaxLen  = pDBColumnInfo[j].ulColumnSize + 1;
                                 // + 1 for null terminator
        pBindings[j].dwFlags   = 0;
        pBindings[j].wType      = pDBColumnInfo[j].wType;
        pBindings[j].bPrecision = pDBColumnInfo[j].bPrecision;
        pBindings[j].bScale     = pDBColumnInfo[j].bScale;

        //Recalculate the next buffer offset.
        ConsumerBufferColOffset = ConsumerBufferColOffset + 
                                    pDBColumnInfo[j].ulColumnSize;
    };
        /*
        Indicate that the first field is used as a bookmark by setting
        dwFlags to DBCOLUMNFLAGS_ISBOOKMARK.
        */
        pBindings[0].dwFlags = DBCOLUMNFLAGS_ISBOOKMARK;

    //Get IAccessor interface.
    hr = pIRowset->QueryInterface(
                            IID_IAccessor, 
                            (void **)&pIAccessor);
    if (FAILED(hr))
    {
        printf("Failed to get IAccessor interface.\n");
    }
    //Create accessor.
    hr = pIAccessor->CreateAccessor(
                        DBACCESSOR_ROWDATA, 
                        lNumCols, 
                        pBindings,
                        0,
                        &hAccessor,
                        NULL);
    if(FAILED(hr))
    {
        printf("Failed to create an accessor.\n");
    }

    HRESULT hr = pIRowset->QueryInterface(
                                IID_IRowsetLocate, 
                                (void **) &pIRowsetLocate);
    if (FAILED(hr))
    {
        printf("Failed to get IRowsetLocate interface.\n");
    }
        hr = pIRowsetLocate->GetRowsAt(
                                    0,                          
                                    NULL,                       
                                    sizeof(int),                
                                    (BYTE *) &iBookmark,        
                                    0,                          
                                    1,                          
                                    &lNumRowsRetrieved,         
                                    &pRows);                 

        if (FAILED(hr))
        {
            printf("Calling the GetRowsAt method failed.\n");
        }
    //Create buffer and retrieve data.
    pBuffer = new char[ConsumerBufferColOffset];
    memset(pBuffer, 0, ConsumerBufferColOffset);

    hr = pIRowset->GetData(hRows[0], hAccessor, pBuffer);
    if (FAILED(hr))
    {
        printf("Failed GetDataCall.\n");
    }
    
    printf("%d\t%s%s\n", &pBuffer[pBindings[0].obValue], 
                        &pBuffer[pBindings[1].obValue],
                        &pBuffer[pBindings[2].obValue]);
               
    pIRowset->ReleaseRows(lNumRowsRetrieved, 
                            hRows, 
                            NULL, 
                            NULL, 
                            NULL);
   
    //Free  all allocated memory.
    delete [] pBuffer;
    pIAccessor->ReleaseAccessor(hAccessor, NULL);
    pIAccessor->Release();
    delete [] pBindings;
} //ProcessResultSet.