获取行数据

IRowset接口是Rowset对象的基本接口。这个接口提供了顺序获取和管理行数据的方法。用户使用IRowset的方法进行基本的行操作,比如获取和释放行数据,获取列值等等。

当用户创建了Rowset对象,通常第一步是通过IRowsetInfo::GetProperties读取Rowset的属性,了解Rowset的行为和能力。然后用户可以通过IColumnsInfo或者IColumnsRowset接口获得Rowset的列信息,具体内容为:

Rowset包含的列数

一个DBCOLUMNINFO结构数组,每个元素表示一列

一个包含所有字符串的缓存的指针

收集到Rowset的列信息后,用户可以根据这些信息和应用的需求,构建一个绑定数组作为参数传递给IAccessor::CreateAccessor,这样可以创建一个Accessor,它代表了用户创建的列信息绑定。用户可以创建多个Accessor来获取不同的列数据。只要Rowset对象还存在,Accessor能够随时创建和释放。

用户通过IRowset::GetNextRows或者IRowsetLocate::GetRowsAt来获取Rowset中的行数据。这些函数把行数据从数据库读取出来存入OLE DB的行缓存中。用户不能直接访问OLE DB的行缓存。用户必须使用IRowset::GetData将OLE DB的行缓存复制到用户的缓存中,同样,用户使用IRowsetChange::SetData来将用户缓存中的要改变的行数据复制到OLE DB的行缓存中。

用户调用GetData,传入一个标识行的句柄,一个标识Accessor的句柄,一个用户分配的缓存指针。GetData根据Accessor所规定的列数据绑定,将行标识句柄标识的行的数据写入用户的缓存。用户可以在同一行上使用不同的Accessor多次调用GetData,也就是说,用户可以获取同一份行数据的不同拷贝。

当用户获取或者更新了行数据以后,它调用ReleaseRows来释放OLE DB的行缓存。当用户对Rowset的对象操作完成后,可调用IAccessor::ReleaseAccessor来释放acceoosr,然后调用IUnknown::Release方法来释放Rowset对象本身。当Rowset对象被释放后,所有的行句柄信息和Accessor都将被释放。

GetNextRows方法会顺序的读取Rowset中的所有行数据,不过GetNextRows可以使用skip参数来忽略掉某些行。另外,FindNextRow,Seek,RestartPosition都可以改变GetNextRows的顺序读取方式。

下面举例说明如何从Rowset中提取行数据。

/*

Example shows how to fetch rows from a result set.

*/

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;

ICommandText* pICommandText = NULL;

IRowset* pIRowset = NULL;

IColumnsInfo* pIColumnsInfo = NULL;

DBCOLUMNINFO* pDBColumnInfo = NULL;

IAccessor* pIAccessor = NULL;

DBPROP InitProperties[4];

DBPROPSET rgInitPropSet[1];

ULONG i, j;

HRESULT hr;

LONG cNumRows = 0;

ULONG lNumCols;

WCHAR* pStringsBuffer;

DBBINDING* pBindings;

ULONG ConsumerBufColOffset = 0;

HACCESSOR hAccessor;

ULONG lNumRowsRetrieved;

HROW hRows[10];

HROW* pRows = &hRows[0];

BYTE* pBuffer;

void main()

{

//Here is the command to execute.

WCHAR* wCmdString

= OLESTR(" SELECT title, price FROM titles WHERE

royalty > 14");

// Call a function to initialize and establish connection.

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";

}

//Use SetCommandText() to 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";

}

//Process the result set.

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"; */

} //endif.

pIDBInitialize->Release();

//Release the COM library.

CoUninitialize();

};

//--------------------------------------------------------------------

void InitializeAndEstablishConnection()

{

//Initialize the COM library.

CoInitialize(NULL);

//Obtain access to the SHENTONGOLEDB provider.

hr = CoCreateInstance(CLSID_OSCAROLEDB,

NULL,

CLSCTX_INPROC_SERVER,

IID_IDBInitialize,

(void **) &pIDBInitialize);

if(FAILED(hr))

{

printf("Failed to get IDBInitialize interface.\n");

} //end if

/*

Initialize the property values needed

to establish the connection.

*/

for(i = 0; i < 4; i++)

VariantInit(&InitProperties[i].vValue);

//Server name.

InitProperties[0].dwPropertyID = DBPROP_INIT_DATASOURCE;

InitProperties[0].vValue.vt = VT_BSTR;

InitProperties[0].vValue.bstrVal=

SysAllocString(L"testdb");

InitProperties[0].dwOptions = DBPROPOPTIONS_REQUIRED;

InitProperties[0].colid = DB_NULLID;

//Database.

InitProperties[1].dwPropertyID = DBPROP_INIT_LOCATION;

InitProperties[1].vValue.vt = VT_BSTR;

InitProperties[1].vValue.bstrVal= SysAllocString(L"192.9.200.10");

InitProperties[1].dwOptions = DBPROPOPTIONS_REQUIRED;

InitProperties[1].colid = DB_NULLID;

//Username (login).

InitProperties[2].dwPropertyID = DBPROP_AUTH_USERID;

InitProperties[2].vValue.vt = VT_BSTR;

InitProperties[2].vValue.bstrVal= SysAllocString(L"login");

InitProperties[2].dwOptions = DBPROPOPTIONS_REQUIRED;

InitProperties[2].colid = DB_NULLID;

//Password.

InitProperties[3].dwPropertyID = DBPROP_AUTH_PASSWORD;

InitProperties[3].vValue.vt = VT_BSTR;

InitProperties[3].vValue.bstrVal= SysAllocString(L"Password");

InitProperties[3].dwOptions = DBPROPOPTIONS_REQUIRED;

InitProperties[3].colid = DB_NULLID;

/*

Now that the properties are set, construct the DBPROPSET structure

(rgInitPropSet). The DBPROPSET structure is used to pass an array

of DBPROP structures (InitProperties) to the SetProperties method.

*/

rgInitPropSet[0].guidPropertySet = DBPROPSET_DBINIT;

rgInitPropSet[0].cProperties = 4;

rgInitPropSet[0].rgProperties = InitProperties;

//Set initialization properties.

hr = pIDBInitialize->QueryInterface(IID_IDBProperties,

(void **)&pIDBProperties);

if(FAILED(hr))

{

cout << "Failed to get IDBProperties interface.\n";

}

hr = pIDBProperties->SetProperties(1, rgInitPropSet);

if(FAILED(hr))

{

cout << "Failed to set initialization properties.\n";

} //end if

pIDBProperties->Release();

//Now establish the connection to the data source.

if(FAILED(pIDBInitialize->Initialize()))

{

cout << "Problem in establishing connection to the data

source.\n";

}

} //end of InitializeAndEstablishConnection.

//--------------------------------------------------------------------

//Retrieve and display data resulting from a query.

void ProcessResultSet()

{

//Obtain access to the IColumnInfo interface, from the Rowset

object.

hr = pIRowset->QueryInterface(IID_IColumnsInfo,

(void **)&pIColumnsInfo);

if(FAILED(hr))

{

cout << "Failed to get IColumnsInfo interface.\n";

} //end if

//Retrieve the column information.

pIColumnsInfo->GetColumnInfo(&lNumCols,

&pDBColumnInfo,

&pStringsBuffer);

//Free the column information interface.

pIColumnsInfo->Release();

//Create a DBBINDING array.

pBindings = new DBBINDING[lNumCols];

//Using the ColumnInfo structure, fill out the pBindings array.

for(j=0; j<lNumCols; j++) {

pBindings[j].iOrdinal = j+1;

pBindings[j].obValue = ConsumerBufColOffset;

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;

pBindings[j].dwFlags = 0;

pBindings[j].wType = pDBColumnInfo[j].wType;

pBindings[j].bPrecision = pDBColumnInfo[j].bPrecision;

pBindings[j].bScale = pDBColumnInfo[j].bScale;

//Compute the next buffer offset.

ConsumerBufColOffset = ConsumerBufColOffset +

pDBColumnInfo[j].ulColumnSize;

};

//Get the IAccessor interface.

hr = pIRowset->QueryInterface(IID_IAccessor, (void **)

&pIAccessor);

if(FAILED(hr))

{

cout << "Failed to obtain IAccessor interface.\n";

}

//Create an accessor from the set of bindings (pBindings).

pIAccessor->CreateAccessor(DBACCESSOR_ROWDATA,

lNumCols,

pBindings,

0,

&hAccessor,

NULL);

//Print column names.

for(j=0; j<lNumCols; j++) {

printf("%-40S", pDBColumnInfo[j].pwszName);

};

//Get a set of 10 rows.

pIRowset->GetNextRows(

NULL,

0,

10,

&lNumRowsRetrieved,

&pRows);

//Allocate space for the row buffer.

pBuffer = new BYTE[ConsumerBufColOffset];

//Display the rows.

while(lNumRowsRetrieved > 0) {

//For each row, print the column data.

for(j=0; j<lNumRowsRetrieved; j++) {

//Clear the buffer.

memset(pBuffer, 0, ConsumerBufColOffset);

//Get the row data values.

pIRowset->GetData(hRows[j], hAccessor, pBuffer);

//Print title and price values.

printf("%-40s%f\n", &pBuffer[pBindings[0].obValue],

(FLOAT) Buffer[pBindings[0].obValue]);

}; //for.

//Release the rows retrieved.

pIRowset->ReleaseRows(lNumRowsRetrieved,

hRows,

NULL,

NULL,

NULL);

//Get the next set of 10 rows.

pIRowset->GetNextRows(NULL,

0,

10,

&lNumRowsRetrieved,

&pRows);

}; //while lNumRowsRetrieved > 0.

//Free up all allocated memory.

delete [] pBuffer;

pIAccessor->ReleaseAccessor(hAccessor, NULL);

pIAccessor->Release();

delete [] pBindings;

} //ProcessResultSet.