How to retrieve rows using bookmarks (OLE DB)

How to Install SQL Server 2000

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.