Fetching Rows

OLE DB and SQL Server

OLE DB and SQL Server

Fetching Rows

The IRowset interface is the base rowset interface. The IRowset interface provides methods for fetching rows sequentially, getting the data from those rows, and managing rows. Consumers use the methods in IRowset for all basic rowset operations, including fetching and releasing rows and getting column values.

When a consumer gets an interface pointer on a rowset, usually the first step is to determine the capabilities of the rowset by using the IRowsetInfo::GetProperties method. This returns information about the interfaces exposed by the rowset as well as capabilities of the rowset that do not show up as distinct interfaces, such as the maximum number of active rows and how many rows can have pending updates at the same time.

The next step for consumers is to determine the characteristics, or metadata, of the columns in the rowset. For this they use the IColumnsInfo or IColumnsRowset methods, for simple or extended column information, respectively. The GetColumnInfo method returns:

  • The number of columns in the result set.

  • An array of DBCOLUMNINFO structures, one per column.

    The order of the structures is the order in which the columns appear in the rowset. Each DBCOLUMNINFO structure includes column meta data, such as column name, ordinal of the column, maximum possible length of a value in the column, data type of the column, precision, and length.

  • The pointer to a storage for all string values within a single allocation block.

The consumer determines which columns it needs, either from the meta data or on the basis of the text command that generated the rowset. It determines the ordinals of the needed columns from the ordering of the column information returned by IColumnsInfo or from the ordinals in the column meta data rowset returned by IColumnsRowset.

The IColumnsRowset and IColumnsInfo interfaces are used to extract information about the columns in the rowset. The IColumnsInfo interface returns a limited set of information, whereas IColumnsRowset provides all the meta data.

Note  In SQL Server version 7.0 and earlier, the optional meta data column DBCOLUMN_COMPUTEMODE returned by IColumnsInfo::GetColumnsInfo returns DBSTATUS_S_ISNULL (instead of the values describing if the column is computed or not) because it cannot be determined if the underlying column is computed column or not.

The ordinals are used to specify a binding to a column. A binding is a structure that associates an element of the consumer's structure with a column. The binding can bind the data value, length, and status value of the column.

A set of bindings is gathered together in an accessor, which is created with the IAccessor::CreateAccessor method. An accessor can contain multiple bindings so that the data for multiple columns can be retrieved or set in a single call. The consumer can create several accessors to match different usage patterns in different parts of the application. It can create and release accessors at any time while the rowset remains in existence.

To fetch rows from the database, the consumer calls a method, such as IRowset::GetNextRows or IRowsetLocate::GetRowsAt. These fetch operations put row data from the server into the row buffer of the provider. The consumer does not have direct access to the row buffer of the provider. The consumer uses IRowset::GetData to copy data from the buffer of the provider to the consumer buffer and IRowsetChange::SetData to copy data changes from the consumer buffer to the provider buffer.

The consumer calls the GetData method and passes it the handle to a row, the handle to an accessor, and a pointer to a consumer-allocated buffer. GetData converts the data and returns the columns as specified in the bindings used to create the accessor. The consumer can call GetData more than once for a row, using different accessors and buffers; therefore, the consumer can have multiple copies of the same data.

Data from variable-length columns can be treated several ways. First, such columns can be bound to a finite section of the consumer's structure, which causes truncation when the length of the data exceeds the length of the buffer. The consumer can determine that truncation has occurred by checking for the status DBSTATUS_S_TRUNCATED. The returned length is always the true length in bytes, so the consumer also can determine how much data was truncated.

When the consumer is finished fetching or updating rows, it releases them with the ReleaseRows method. This releases resources from the copy of the rows in the rowset and makes room for new rows. The consumer can then repeat its cycle of fetching or creating rows and accessing the data in them.

When the consumer is done with the rowset, it calls the IAccessor::ReleaseAccessor method to release any accessor. It calls the IUnknown::Release method on all interfaces exposed by the rowset to release the rowset. When the rowset is released, it forces the release of any remaining rows or accessors the consumer may hold.