MDAC 2.5 SDK - Technical Articles


 

OLE DB Leveling

Choosing the Right Interfaces

Abstract

OLE DB defines a comprehensive set of interfaces for accessing a diverse range of data types, located in a variety of data stores. The OLE DB Programmer's Reference can be intimidating in size, but no one data store is expected to support all of the functionality defined in the reference. OLE DB data providers only expose the interfaces that reflect the natural functionality of their data store. Providers all support a base level of functionality. Above that base level, common service components provide interoperability through generic implementations of extensions such as scrolling, or predicate-based positioning if the provider doesn't support them.

Defining a minimal level of support exposed by all data stores, along with a common set of extended services, means:

Introduction: OLE DB as a Component Technology

To meet its goal of providing data access to all types of data in a COM (Component Object Model) environment, OLE DB is designed as a component technology. In OLE DB, data stores expose the interfaces that reflect their native functionality. Common components can be built on top of those interfaces to expose more robust data models. To define a component architecture, OLE DB identifies common characteristics between different data providers and services, and defines common interfaces to expose those characteristics. So, for example, while a rowset may be obtained through a number of very different mechanisms, the end result is still a rowset, with well-defined interfaces, methods and characteristics. With OLE DB, navigating the result of a complex multitable join is no different than navigating the result of a text file containing tabular data. Defining common interfaces in this manner allows components to more efficiently augment the individual data provider's native functionality.

Once the base functionality is defined, the next step is to view the additional functionality as incremental additions to this base functionality. Thus, the more sophisticated providers can expose these advanced features in addition to the base level interfaces. Furthermore, individual service components can be built to implement these features on top of the simpler providers.

Consumers

Developers writing OLE DB consumers can choose their level of interoperability with OLE DB providers. Consumers may be written to consume a specific provider, in which case they are designed to be aware of the functionality of the provider. Or they may be written to consume generic providers. In order to consume generic providers, the consumer may do one of the following:

Base Consumer Functionality

Table 1 describes the minimum level of functionality that a consumer can expect to be supported when talking to any OLE DB provider. The table is broken into three columns:

Table 1   Base Consumer Interfaces

Object Base interfaces Updatable
Root Enumerator IDBInitialize1  
  IParseDisplayName1  
  ISourcesRowset1  
Data Links IDataInitialize1  
  IPromptInitialize1  
RowPosition IRowPosition1  
DataSource IDBCreateSession  
  IDBInitialize  
  IDBProperties  
  IPersist  
DataSource Behavior DBPROP_INIT_PROMPT2  
Session IGetDataSource  
  IOpenRowset  
  ISessionProperties  
Rowset IAccessor IRowsetChange
  IColumnsInfo  
  IConvertType  
  IRowset  
  IRowsetFind  
  IRowsetIdentity  
  IRowsetInfo  
  IRowsetLocate  
  IRowsetScroll  
Rowset Behavior DBPROP_ CANHOLDROWS DBPROP_ REMOVEDELETED
  DBPROP_ CANFETCHBACKWARDS DBPROP_ OWNUPDATEDELETE
  DBPROP_ CANSCROLLBACKWARDS DBPROP_ OWNINSERT

1   These interfaces are always supported by common components in the SDK. They are never implemented directly by providers.

2   DBPROP_INIT_PROMPT is only required if any initialization properties are required in order to connect to the provider. If calling Initialize() can succeed on a freshly created Datasource, the provider does not need to support this property.

Consumers are guaranteed to get the above functionality in one of three ways:

Providers

An OLE DB provider exposes OLE DB interfaces over some type of data. OLE DB providers include everything from a full SQL DBMS to a text file or data stream. Obviously these data providers have different functionality, and it's important not to limit that functionality. But at the same time it's not reasonable to expect all providers that expose simple tabular data to implement a full-blown query engine as well.

Providers support the native functionality of the data that they expose. This includes at least the functionality described in the section "Minimum Provider Functionality" in this paper.  Additional interfaces should be implemented as appropriate. If the provider natively supports all of the functionality listed in the section "Base Consumer Functionality," then service components won't be needed to provide the minimal consumer functionality. In addition, providers may expose interfaces for the extended functionality described in the section "Extended Interfaces."

All providers must be either apartment, rental, or free threaded, and must support aggregation of the DataSource, Session, and Rowset objects. If applicable, providers must support the aggregation of the Command and View objects.

Providers must support data conversions to the types returned in IColumnsInfo::GetColumnsInfo or IColumnsRowset::GetColumnsRowset for rowset columns, and ICommandWithParameters::GetParameterInfo for parameters, as well as DBTYPE_WSTR for all column or parameter values other than those described as objects. Providers that support binding to objects as IStream or ILockBytes must also support binding to those columns as ISequentialStream.

Minimum Provider Functionality

It is important for provider writers to implement the full set of interfaces that apply to their particular type of data. At a minimum, the provider must implement the interfaces and behavior listed in Table 2 to be considered a generic OLE DB provider. Providers implementing the minimum provider functionality can rely on common service components available in the SDK to implement the  base consumer functionality, as shown in Figure 1.

Figure 1   Base application using service components to talk to a minimum provider

Table 2   Minimum Provider Interfaces

Object Any OLE DB provider Updatable providers
DataSource IDBCreateSession  
  IDBInitialize  
  IDBProperties  
  IPersist  
Session IGetDataSource  
  IOpenRowset  
  ISessionProperties  
Rowset IAccessor IConnectionPointContainer for IRowsetNotify1
  IConvertType IRowsetChange
  IColumnsInfo  
  IRowset  
  IRowsetIdentity  
  IRowsetInfo  
Rowset Behavior DBPROP_CANHOLDROWS DBPROP_ OWNUPDATEDELETE
  DBPROP_ DATASOURCEREADONLY DBPROP_OWNINSERT
  DBPROP_IACCESSOR DBPROP_ REMOVEDELETED
  DBPROP_ICOLUMNSINFO  
  DBPROP_ICONVERTTYPE  
  DBPROP_IROWSET  
  DBPROP_ IROWSETIDENTITY  
  DBPROP_IROWSETINFO  

1   Supporting IConnectionPointContainer for IRowsetNotify is not strictly required for OLE DB 2.0 providers to satisfy the minimum requirements for an updatable provider. However, updatable providers are strongly encouraged to expose this connection point as some consumers will be forced to treat providers as read-only if they do not support rowset notifications by exposing the connection point for IRowsetNotify.

Supporting an interface means supporting all methods within that interface. No methods return E_NOTIMPL.

Supporting a property means supporting the setting of and associated behavior of all possible values for a property.

Supporting the required rowset properties means that setting any combination of the required properties must yield a rowset that reflects at least those properties. It does not mean that those properties are always true for any rowset if the property has not been requested by the user.

Base Providers

Providers that implement the full set of base interfaces can be consumed by general consumers without the support of additional service components, as shown in Figure 2.

Figure 2  Base application talking directly to a base provider

Providers implementing the functionality described in Table 3 in addition to the minimum provider functionality are consumed as base providers.

Table 3   Full Interfaces for Base Providers

Object Any base provider Updatable providers
Rowset IRowsetFind  
  IRowsetLocate  
  IRowsetScroll  
Rowset Behavior DBPROP_ CANSCROLLBACKWARDS1  
  DBPROP_ CANFETCHBACKWARDS1  

1   Providers that support the property DBPROP_CANSCROLLBACKWARDS must also support the property DBPROP_CANFETCHBACKWARDS.

Extended Interfaces

General purpose providers may support additional functionality. It is advantageous that providers support as many extended interfaces as apply to their particular type of data.

In addition to common interface extensions, providers may expose specialized interfaces for the following sets of extended functionality:

Table 4   Extended Interfaces

Object Any provider Updatable providers Transacted providers
DataSource IConnectionPointContainer for IDBAsynchNotify    
  IDBAsynchStatus    
  IDataSourceAdmin    
  IDBInfo2    
  IPersistFile    
  ISupportErrorInfo    
Session IAlterIndex   ITransactionLocal
  IAlterTable   ITransactionJoin
  IDBSchemaRowset   ITransactionObject
  IDBView1    
  IDBCreateCommand2    
  IIndexDefinition    
  ITableDefinition    
  ISupportErrorInfo    
View1 IViewFilter    
  IViewSort    
  IColumnsInfo    
  IAccessor    
  ISupportErrorInfo    
  IViewRowset    
  IViewChapter    
Command2 IAccessor    
  ICommand    
  ICommandPersist    
  ICommandText    
  IColumnsInfo    
  ICommandPrepare    
  IColumnsRowset    
  ICommandProperties    
  ICommandWithParameters    
  IConvertType    
  ISupportErrorInfo    
Command Behavior MAXTABLESINSELECT>1    
Custom Error ISQLErrorInfo    
Multiple Results IMultipleResults    
Rowset IConnectionPointContainer for

-IRowsetNotify

-IDBAsynchNotify

IRowsetResynch  
  IColumnsRowset    
  IChapteredRowset1    
  IDBAsynchStatus IRowsetUpdate  
  IRowsetChapterMember    
  IRowsetIdentity    
  IRowsetLocate    
  IRowsetView1    
  IRowsetIndex3    
  IRowsetIndex3    
  ISupportErrorInfo    
Rowset Behavior DBPROP_ LITERALBOOKMARKS DBPROP_CHANGE INSERTEDROWS DBPROP_ COMMITPRESERVE
  DBPROP_ ORDEREDBOOKMARKS DBPROP_RETURN PENDINGROWS DBPROP_ ABORTPRESERVE
  DBPROP_ LITERALIDENTITY DBPROP_ IMMOBILEROWS  
  DBPROP_ BOOKMARKSKIPPED    
  DBPROP_OTHERINSERT    
  DBPROP_ OTHERUPDATEDELETE    
  DBPROP_ STRONGIDENTITY    
BLOB Support DBPROP_OLEOBJECTS    
  DBPROP_MULTIPLE STORAGEOBJECTS    
  DBPROP_STRUCTURED STORAGE    
  ISequentialStream    
  IStream    
  IStorage    
  ILockBytes    
  DBPROP_BLOCKING STORAGEOBJECTS=FALSE    

1   Extended functionality that may be exposed by providers which support rowset processing.

2   Extended functionality that may be exposed by providers which support commands.

3   Extended functionality that may be exposed by providers which support index navigation.

Generic consumers must be prepared for providers that don't support the extended interfaces. Consumers can handle such providers in several different ways: