使用书签检索行 (OLE DB)

使用者将绑定结构的 dwFlag 字段值设置为 DBCOLUMNSINFO_ISBOOKMARK,以指示将该列用作书签。 使用者还可将行集属性 DBPROP_BOOKMARKS 设置为 VARIANT_TRUE。 这允许在行集中出现第 0 列。 然后,使用 IRowsetLocate::GetRowsAt 方法提取行(起始行的位置为书签加上一个偏移量得到的位置)。

安全说明安全说明

请尽可能使用 Windows 身份验证。 如果 Windows 身份验证不可用,请在运行时提示用户输入其凭据。 不要将凭据存储在一个文件中。 如果必须保存凭据,则应当用 Win32 crypto API(Win32 加密 API)进行加密。

使用书签检索行

  1. 建立与数据源的连接。

  2. 将行集 DBPROP_IRowsetLocate 属性设置为 VARIANT_TRUE。

  3. 执行命令。

  4. 对于将用作书签的列,请将绑定结构的 dwFlag 字段设置为 DBCOLUMNSINFO_ISBOOKMARK 标记。

  5. 使用 IRowsetLocate::GetRowsAt 提取行,起始行的位置为书签加上一个偏移量得到的位置。

示例

此示例显示如何使用书签提取行。 IA64 平台不支持此示例。

在该示例中,将从执行 SELECT 语句产生的结果集中检索第五行。

此示例要求使用 AdventureWorks 示例数据库,可以从 Microsoft SQL Server Samples and Community Projects(Microsoft SQL Server 示例和社区项目)主页下载该数据库。

使用 ole32.lib 和 oleaut32.lib 编译并执行以下 C++ 代码列表。 此应用程序连接到您的计算机上默认的 SQL Server 实例。 在某些 Windows 操作系统上,您需要将 (localhost) 或 (local) 更改为您的 SQL Server 实例的名称。 若要连接到命名实例,请将连接字符串从 L"(local)" 更改为 L"(local)\\name",其中 name 是命名实例。 默认情况下,SQL Server Express 安装在命名实例中。 请确保您的 INCLUDE 环境变量包括含有 sqlncli.h 的目录。

// compile with: ole32.lib oleaut32.lib
int InitializeAndEstablishConnection();
int ProcessResultSet();

#define UNICODE
#define _UNICODE
#define DBINITCONSTANTS
#define INITGUID
#define OLEDBVER 0x0250   // to include correct interfaces

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

using namespace std;

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       hresult;
DBROWCOUNT    cNumRows = 0;
DBORDINAL     lNumCols;
WCHAR*        pStringsBuffer;
DBBINDING*    pBindings;
DBLENGTH      ConsumerBufferColOffset = 0;
HACCESSOR     hAccessor;
DBCOUNTITEM   lNumRowsRetrieved;
HROW          hRows[5];         
HROW*         pRows = &hRows[0];
char*         pBuffer;

int main() {
   // The command to execute.
   // WCHAR* wCmdString = OLESTR(" SELECT title_id, title FROM titles ");
   WCHAR* wCmdString = OLESTR(" SELECT Name FROM Production.Product");

   // Initialize and establish a connection to the data source.
   if (InitializeAndEstablishConnection() == -1) {
      // Handle error.
      cout << "Failed to initialize and connect to the server.\n";
      return -1;
   }

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

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

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

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

   // 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.
   hresult = pICommandText->QueryInterface( IID_ICommandProperties,(void **)&pICommandProperties);
   if (FAILED(hresult)) {
      printf("Failed to get ICommandProperties to set rowset properties.\n");
      // Release any references and return.
      return -1;
   }

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

   pICommandProperties->Release();

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

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

   ProcessResultSet(); 

   pIRowset->Release();

   // Free up memory.
   pICommandText->Release();
   pIDBCreateCommand->Release();
   pIDBCreateSession->Release();

   pIDBInitialize->Uninitialize();
   pIDBInitialize->Release();

   // Release COM library.
   CoUninitialize();

   return -1;
}

int InitializeAndEstablishConnection() {    
   // Initialize the COM library.
   CoInitialize(NULL);

   // Obtain access to the SQL Server Native Client OLe DB provider.
   CoCreateInstance( CLSID_SQLNCLI11, NULL, CLSCTX_INPROC_SERVER, IID_IDBInitialize, (void **) &pIDBInitialize);

   // Initialize the property values that are the same for each property.
   for ( i = 0 ; i < 4 ; 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(L"(local)");

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

   InitProperties[2].dwPropertyID = DBPROP_AUTH_INTEGRATED; 
   InitProperties[2].vValue.vt = VT_BSTR;
   InitProperties[2].vValue.bstrVal = SysAllocString(L"SSPI");

   // 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);

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

   pIDBProperties->Release();

   // Call the initialization method to establish the connection.
   if (FAILED(pIDBInitialize->Initialize())) {
      cout << "Problem initializing and connecting to the data source.\n";
      // Handle error.
      return -1;
   }

   return 0;
}

#ifdef _WIN64
#define BUFFER_ALIGNMENT 8
#else
#define BUFFER_ALIGNMENT 4
#endif

#define ROUND_UP(value) (value + (BUFFER_ALIGNMENT - 1) & ~(BUFFER_ALIGNMENT - 1))

int ProcessResultSet() {
   HRESULT hr;

   // Retrieve 5th row from the rowset (for example).
   DBBKMARK iBookmark = 5;

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

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

   // Create a DBBINDING array.
   pBindings = new DBBINDING[lNumCols];
   if (!(pBindings /* = new DBBINDING[lNumCols] */ )) {
      // Handle error.
      return -1;
   }

   // 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;
  ConsumerBufferColOffset = ROUND_UP(ConsumerBufferColOffset);

   };
   // 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");
      // Handle error.
      return -1;
   }

   // Create accessor.
   hr = pIAccessor->CreateAccessor( DBACCESSOR_ROWDATA,
                                    lNumCols,
                                    pBindings,
                                    0,
                                    &hAccessor,
                                    NULL);

   if (FAILED(hr)) {
      printf("Failed to create an accessor.\n");
      // Handle error.
      return -1;
   }

   hr = pIRowset->QueryInterface( IID_IRowsetLocate, (void **) &pIRowsetLocate);
   if (FAILED(hr)) {
      printf("Failed to get IRowsetLocate interface.\n");
      // Handle error.
      return -1;
   }

   hr = pIRowsetLocate->GetRowsAt( 0,
                                   NULL,
                                   sizeof(DBBKMARK),
                                   (BYTE *) &iBookmark,
                                   0,
                                   1,
                                   &lNumRowsRetrieved,
                                   &pRows);

   if (FAILED(hr)) {
      printf("Calling the GetRowsAt method failed.\n");
      // Handle error.
      return -1;
   }

   // Create buffer and retrieve data.
   pBuffer = new char[ConsumerBufferColOffset];
   if (!(pBuffer /* = new char[ConsumerBufferColOffset] */ )) {
      // Handle error.
      return -1;
   }

   memset(pBuffer, 0, ConsumerBufferColOffset);

   hr = pIRowset->GetData(hRows[0], hAccessor, pBuffer);
   if (FAILED(hr)) {
      printf("Failed GetDataCall.\n");
      // Handle error.
      return -1;
   }

   char szTitle[7] = {0};
   strncpy_s(szTitle, &pBuffer[pBindings[1].obValue], 6);

   printf("%S\n", &pBuffer[pBindings[1].obValue]);

   pIRowset->ReleaseRows(lNumRowsRetrieved, hRows, NULL, NULL, NULL);

   // Release allocated memory.
   delete [] pBuffer;
   pIAccessor->ReleaseAccessor(hAccessor, NULL);
   pIAccessor->Release();
   delete [] pBindings;

   return 0;
}