MDAC 2.5 SDK - OLE DB Programmer's Reference
Chapter 4: Rowsets
Bookmarks are placeholders that enable the consumer to return quickly to a row. Consumers that use bookmarks to identify rows to a provider should treat bookmarks as opaque binary values. Consumers should not try to interpret these values. Bookmarks are returned in columns in the rowset. An application retrieves them in the same manner as it retrieves data from any other column in the rowset. That is, it creates an accessor that binds to the bookmark column and calls IRowset::GetData using this accessor.
Bookmarks are valid only during the lifetime of the rowset to which they refer. For indexes that use bookmarks to reference rows in a base table, the bookmark returned as the pointer column in the index rowset is a valid bookmark in the rowset built over the base table; therefore, the bookmark is valid for the table rowset.
Bookmark columns have DBCOLUMNFLAGS_ISBOOKMARK set in their column information. A bookmark can be of a fixed scalar type such as DBTYPE_I4, or it can be a character sequence that appears, for example, as a DBTYPE_STR column. There is no specialized bookmark data type. Providers can return any valid type indicator in IColumnsInfo::GetColumnInfo for a bookmark column.
Bookmarks can always be read and passed as binary values. When using a bookmark to identify a row to a provider, consumers can always bind bookmark values as DBTYPE_BYTES. Alternatively, if the consumer knows the actual DBTYPE of the bookmark, it can bind to that specific type. For more information about data types, see Appendix A, "Data Types."
Bookmarks are not the same thing as primary keys or row IDs (see "Bookmark Types," later in this chapter). They can be related, and it is possible to use a primary key or row ID to implement a bookmark, but often there are more compact or swifter bookmark schemes that work only for the current contents of the rowset. It is important to take advantage of those optimizations in places such as command optimization or result set navigation. Furthermore, bookmarks are not necessarily the same as row handles because they may have ordering semantics or might be used to track nonresident members of very large rowsets.
A rowset implements only one kind of bookmark. The provider may have incompatible solutions for implementing primary key or row ID semantics on bookmarks, so it cannot support both simultaneously.
Bookmarks operate as logical pointers. The encapsulation allows transient, rowset-level bookmarks to be implemented as pointers, although this would likely be used only for rowsets small enough to be efficiently instantiated.
If IRowsetLocate or one of its direct descendants is present on a rowset, column 0 is the bookmark for the rows. Column 0 is present in a rowset only if the rowset has the property DBPROP_BOOKMARKS set to VARIANT_TRUE. Reading this column yields a bookmark value that can be used to position itself again to the same row. This is called the self bookmark. Other bookmark columns referring to the same rowset, such as a Spouse column in a query about people, are not self bookmarks.
Bookmark columns can be returned on any rowset, regardless of its source (for example, ICommand::Execute, IOpenRowset::OpenRowset, IColumnsRowset::GetColumnsRowset, or IDBSchemaRowset::GetRowset) or whether bookmarks were requested.
The DBIDs of the bookmark columns in a rowset are based on a property set identified by the GUID DBCOL_SPECIALCOL. These DBIDs are constructed as follows:
The DBIDs of bookmark columns can be passed to IColumnsInfo::MapColumnIDs to determine the ordinals of those columns. There is no need to pass the DBID of the self bookmark column to MapColumnIDs, because the ordinal of this column is always zero.