使用書籤擷取資料列 (Native Client OLE DB 提供者)
適用於:SQL Server Azure SQL 資料庫 Azure SQL 受控執行個體 Azure Synapse Analytics Platform System (PDW)
取用者會將繫結結構的 dwFlag 欄位值設定為 DBCOLUMNSINFO_ISBOOKMARK,表示該資料行會當做書籤使用。 取用者也會將資料列集屬性 DBPROP_BOOKMARKS 設定為 VARIANT_TRUE。 這可讓資料行 0 出現在資料列集中。 然後使用 IRowsetLocate::GetRowsAt 來擷取資料列,從書籤中指定為位移的資料列開始。
重要
盡可能使用 Windows 驗證。 如果無法使用 Windows 驗證,請提示使用者在執行階段輸入認證。 請避免將認證儲存在檔案中。 如果您必須保存認證,則應該用 Win32 crypto API 加密這些認證。
使用書籤擷取資料列
建立資料來源的連接。
將資料列集 DBPROP_IRowsetLocate 屬性設定為 VARIANT_TRUE。
執行命令。
針對當做書籤使用的資料行,將繫結結構的 dwFlag 欄位設定為 DBCOLUMNSINFO_ISBOOKMARK 旗標。
使用 IRowsetLocate::GetRowsAt 來擷取資料列,從來自書籤的位移所指定的資料列開始。
範例
此範例顯示如何使用書籤提取資料列。 IA64 不支援此範例。
在此範例中,第五個資料列是從執行 SELECT 陳述式所產生之結果集所擷取的。
本文中的 Transact-SQL 程式代碼範例會使用 AdventureWorks2022
或 AdventureWorksDW2022
範例資料庫,您可以從 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;
}