共用方式為


使用書籤擷取資料列 (OLE DB)

取用者會將繫結結構的 dwFlag 欄位值設定為 DBCOLUMNSINFO_ISBOOKMARK,表示該資料行會當做書籤使用。 取用者也會將資料列集屬性 DBPROP_BOOKMARKS 設定為 VARIANT_TRUE。 這可讓資料行 0 出現在資料列集中。 然後使用 IRowsetLocate::GetRowsAt 來提取資料列,從書籤中位移所指定的資料列開始。

安全性注意事項安全性注意事項

盡可能使用 Windows 驗證。 如果無法使用 Windows 驗證,請提示使用者在執行階段輸入認證。 請避免將認證儲存在檔案中。 如果您必須保存認證,則應該用 Win32 crypto API 加密這些認證。

使用書籤擷取資料列

  1. 建立資料來源的連接。

  2. 將資料列集 DBPROP_IRowsetLocate 屬性設定為 VARIANT_TRUE。

  3. 執行命令。

  4. 針對當做書籤使用的資料行,將繫結結構的 dwFlag 欄位設定為 DBCOLUMNSINFO_ISBOOKMARK 旗標。

  5. 使用 IRowsetLocate::GetRowsAt 來提取資料列,從書籤中位移所指定的資料列開始。

範例

此範例顯示如何使用書籤提取資料列。 IA64 不支援此範例。

在此範例中,第五個資料列是從執行 SELECT 陳述式所產生之結果集所擷取的。

此範例需要 AdventureWorks 範例資料庫,您可以從 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;
}