MDAC 2.5 SDK - OLE DB Programmer's Reference
OLE DB Interfaces
IRowset is the base rowset interface. It provides methods for fetching rows sequentially, getting the data from those rows, and managing rows.
IRowset requires IAccessor and IRowsetInfo.
IRowset is a mandatory interface on the rowset object.
Consumers use the methods in IRowset for all basic rowset operations, including fetching and releasing rows and getting column values.
When a consumer first gets an interface pointer on a rowset, usually its first step is to determine the rowset's capabilities using IRowsetInfo::GetProperties. This returns information about the interfaces exposed by the rowset as well as those capabilities of the rowset which 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.
For most consumers, the next step is to determine the characteristics, or metadata, of the columns in the rowset. For this, they use either IColumnsInfo or IColumnsRowset for simple or extended column information, respectively. These interfaces are also available on prepared commands prior to execution, allowing advance planning.
The consumer determines which columns it needs, either from the metadata or on the basis of knowing 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 ordinals in the column metadata rowset returned by IColumnsRowset. Rowset column ordinals start at 1 and are numbered sequentially in increasing order (for example, 1, 2, 3, and so on). When a row object is derived from a rowset, the row-specific column ordinals must come after the rowset column ordinals.
Some consumers do not use a command or do not want to browse the column information; they may know the name or property identifier for the columns they want to use. They call IColumnsInfo::MapColumnIDs to retrieve the column ordinals.
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 column's data value, length, and status value. For more information about bindings, see "Bindings" in Chapter 6, "Getting and Setting Data."
A set of bindings is gathered together in an accessor, which is created with IAccessor::CreateAccessor. 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. For more information about accessors, see "Accessors" in Chapter 6, "Getting and Setting Data."
To fetch rows from the database, the consumer calls a method such as IRowset::GetNextRows or IRowsetLocate::GetRowsAt. To create and initialize a new row to be inserted into the data store, the consumer calls IRowsetChange::InsertRow.
The methods that fetch rows do not actually return data to the consumer. Instead, they return the handles to these rows and a local copy of the rows is stored in the rowset.
After the rows are returned, the consumer can access the data in the rows. The consumer calls IRowset::GetData and passes it the handle to a row, the handle to an accessor, and a pointer to a consumer-allocated buffer. IRowset::GetData converts the data (if it does not match the native provider storage) and returns the columns as specified in the bindings used to create the accessor. The consumer can call IRowset::GetData more than once for a row, using different accessors and buffers; therefore, the consumer can have multiple copies of the same data. For example, if a column contains a text document, the consumer might call IRowset::GetData with an accessor that binds the first 50 bytes of the document. When the user double-clicks on the displayed heading text, the consumer could then call IRowset::GetData with a different accessor to retrieve the entire document.
Data from variable-length columns may 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 whether the status is DBSTATUS_S_TRUNCATED. The returned length is always the true length in bytes, so the consumer also can determine how much data was truncated. Another way to obtain data from such columns is by reference. For example, if a binary column is bound with a type indicator of DBTYPE_BYTES | DBTYPE_BYREF, the provider allocates memory for all of the data in the column and returns this memory to the consumer.
In both cases, it is likely that such large values may be best optimized as deferred columns and accessed only when necessary. Performance varies with different servers, but in general, BLOB columns are stored separately from other records and may be more costly to access than ordinary columns, so they would not routinely be pulled in for browsing or scanning. For more information, see "Deferred Columns" in Chapter 4, "Rowsets."
Another way to handle BLOB columns may be implemented on some providers, and that is to request they be delivered as COM objects that expose ILockBytes, IStorage, ISequentialStream, or IStream interfaces. For more information, see "BLOBs as Storage Objects" in Chapter 7, "BLOBs and COM Objects."
For a description of how to update and delete rows, see Chapter 5, "Updating Data in Rowsets."
When the consumer is finished fetching or updating rows, it releases them with IRowset::ReleaseRows. This releases resources from the rowset's copy of the rows 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 IAccessor::ReleaseAccessor to release any accessors. It calls IUnknown::Release 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. Such handle objects are subordinate to the rowset. That is, they do not take reference counts upon the rowset and cannot cause the rowset to linger beyond the point where all the interfaces for the rowset have been released. The rowset must clean up all such subordinate objects.
Note If the rowset was generated as a result of executing a command that contained output parameters and the provider populates output parameters when the rowset is released (that is, DBPROP_OUTPUTPARAMETERAVAILABILITY is DBPROP_OA_ATROWRELEASE), the memory for the output parameters bound when the command was executed must be valid when the rowset is released. Not doing so is considered a serious programming error and likely will cause a crash.
Method | Description |
AddRefRows | Adds a reference count to an existing row handle. |
GetData | Retrieves data from the rowset's copy of the row. |
GetNextRows | Fetches rows sequentially, remembering the previous position. |
ReleaseRows | Releases rows. |
RestartPosition | Repositions the next fetch position to its initial position; that is, its position when the rowset was first created. |