IRowsetNotify is the callback interface that a consumer must support to connect to local notifications provided by a rowset. The notifications are intended to synchronize objects that are attached to the same rowset instance. The notifications do not reflect changes in underlying shared tables that occur through other programs or users.
The notifications use the standard OLE connection point scheme for events. A rowset supports IConnectionPointContainer and the consumer calls FindConnectionPoint for IID_IRowsetNotify to obtain the correct IConnectionPoint interface. The consumer then advises that connection point to connect and supplies a pointer to the consumer's IRowsetNotify interface.
For more information about notifications, see Chapter 9, "Notifications."
IRowsetNotify is implemented by consumers that require notification. If the command requests support for IConnectionPointContainer, then the rowset is required to support a connection point for IRowsetNotify. Providers should implement this connection point if they expect to work directly with general purpose consumers.
Notification about transactions is not handled through rowsets. There may be multiple rowsets for each transaction, leading to a flood of events. Consumers that need to be notified of transaction activity should connect to the transaction coordinator. For more information, see "Notification Events" in Chapter 12.
IRowset is a prerequisite for notification.
Events may have phases. A phased event is a notification method that is called multiple times, each time with a different phase in the sequence. Some events do not have phases. The phases are similar to phases in two-phase commit protocol, because ensuring that all controls authorize and succeed in handling an event is a problem very similar to ensuring resource managers all agree to, and succeed in, committing a transaction.
In the following descriptions, all consumer objects that connect their IRowsetNotify interface to the rowset are the listeners.
Value | Description |
DBEVENTPHASE_ OKTODO |
Informs a listener of an impending event. All listeners must return S_OK from DBEVENTPHASE_OKTODO for the event to proceed. Any listener can cancel the event by returning S_FALSE. The listener can prepare for the event, but should do nothing irreversible or time consuming. |
If a listener cancels the event, all listeners that have already been called will be called again with DBEVENTPHASE_FAILEDTODO. | |
DBEVENTPHASE_ ABOUTTODO |
Informs a listener that DBEVENTPHASE_OKTODO has been approved and all listeners can proceed to final preparations which must be reversible, but which may be lengthy. The listener should cancel this phase only if it is stopped by an error; it should have cleared all logical objections at the earlier DBEVENTPHASE_OKTODO phase. If a listener cancels the event by returning S_FALSE, all listeners that have already been called will be called again with DBEVENTPHASE_FAILEDTODO. |
DBEVENTPHASE_ SYNCHAFTER |
Informs a listener that the event has occurred after the rowset's copy of the row has been modified, but before the data source has received the change. The listener can synchronize itself with the rowset and ensure that it has no physical reason not to agree to commit the event's changes. If a listener cancels the event by returning S_FALSE, all listeners that have already been called will be called again with DBEVENTPHASE_FAILEDTODO. |
DBEVENTPHASE_ FAILEDTODO |
Informs a listener that has previously been called for this event that the event has failed. The listener should reverse all changes and synchronize with the state of the rowset. |
DBEVENTPHASE_ DIDEVENT |
Informs a listener that all consumers have synchronized themselves and agreed to commit the event's changes. The listener should now commit its changes. It must comply. |
The final phase of an event is always either DBEVENTPHASE_FAILEDTODO or DBEVENTPHASE_DIDEVENT. If the event has no phases, it is equivalent to DBEVENTPHASE_DIDEVENT.
All providers must support the DBEVENTPHASE_FAILEDTODO and DBEVENTPHASE_DIDEVENT phases. Whether providers support DBEVENTPHASE_OKTODO, DBEVENTPHASE_ABOUTTODO, and DBEVENTPHASE_SYNCHAFTER is provider specific, although all but the most simple providers support these phases. To determine which phases a provider supports, a consumer calls IDBProperties::GetProperties for the DBPROP_NOTIFICATIONPHASES property.
If a method changes multiple rows and generates a single-phased event, such as DBREASON_ROW_ACTIVATE or DBREASON_ROW_RELEASE, the provider makes a single call to IRowsetNotify::OnRowChange and passes an array containing the handles of all of the affected rows.
If a method changes multiple rows and generates a multiphased event, such as DBREASON_ROW_UPDATE or DBREASON_ROW_UNDOCHANGE, the number of calls to OnRowChange for each phase depends on the DBPROP_NOTIFICATIONGRANULARITY property.
It is provider-specific whether or not listeners who register after some but not all of the phases of an event have been fired are called for the remaining phases of that event. Listeners must be prepared to get only the final phases of an event upon registering for notifications on an object that is already firing notifications.
Reasons are fine tunings of events. The receiver of events is expected to care only about the general effect of the event, but there may be other effects that more specialized consumers need to know about. The DBEVENT is the basic event, and the DBREASON is a single level of derived subevent.
Important The DBREASON types may be expanded in later versions of OLE DB. IRowsetNotify methods must return S_OK or DB_S_UNWANTEDREASON when they receive a DBREASON value they do not recognize.
Providers are not expected to add new DBREASONs to the defined set. Providers defining new DBREASONs should do so through an entirely new notification interface with its own IID.
The following #define values are valid for DBREASON.
Value | Description |
DBREASON_ROW_ ASYNCHINSERT |
The rowset is being randomly asynchronously populated and one or more rows have been inserted. Only the DBEVENTPHASE_DIDEVENT phase occurs. |
DBREASON_ ROWSET_ FETCHPOSITIONCHANGE |
The next fetch position changed as a result of a call to IRowset::GetNextRows or IRowset::RestartPosition. All phases can occur. |
DBREASON_ ROWSET_RELEASE |
The rowset is being released; that is, its reference count is zero. Only the DBEVENTPHASE_DIDEVENT phase occurs. The rowset no longer exists when this event is sent out, so recipients must not make any calls upon it. Due to OLE rules, there is no way to deny permission to IUnknown::Release. |
DBREASON_ ROWSET_CHANGED |
The rowset metadata has changed. Pointers to interfaces on the rowset remain valid. Providers must revalidate accessors against the metadata, and this might fail due to the changes in the metadata. For example, the accessor might now specify an unsupported conversion. Consumers should free any held row handles when a notification with this DBREASON is generated, because handles to rows are likely to have become invalid. For example, IRowset::GetData might return DB_E_BADROWHANDLE, or IRowsetUpdate::Update might return DBROWSTATUS_E_INVALID. The result of passing such a row handle is provider-specific, although the provider cannot terminate abnormally. Only the DBEVENTPHASE_DIDEVENT phase occurs. |
DBREASON_ COLUMN_SET |
A column value is set. All phases can occur. |
DBREASON_ COLUMN_RECALCULATED |
A calculated column takes a new value because its input columns change. Only the DBEVENTPHASE_DIDEVENT phase occurs. |
DBREASON_ ROW_ACTIVATE |
A function, such as IRowset::GetNextRows or IRowsetLocate::GetRowsAt, caused a new set of rows to be fetched. Only the DBEVENTPHASE_DIDEVENT phase occurs. |
DBREASON_ ROW_RELEASE |
IRowset::ReleaseRows was called and the row's reference count is zero. The array of row handles the provider passed to the listeners is the subset of the original array of row handles passed to ReleaseRows; that is, those row handles for which the reference count is zero. Only the DBEVENTPHASE_DIDEVENT phase occurs. The returned row handles might be invalid and, therefore, should not be used with any methods. |
DBREASON_ ROW_DELETE |
IRowsetChange::DeleteRows has been called. All phases can occur. |
DBREASON_ ROW_FIRSTCHANGE |
The first time any column in the row is set, this notification occurs. It precedes DBREASON_COLUMN_SET. All phases can occur. This event occurs only when the rowset is in delayed update mode. It occurs the first time a column in a row is modified after the row was fetched or after the last call to IRowsetUpdate::Update or IRowsetUpdate::Undo, whichever is more recent. |
DBREASON_ ROW_INSERT |
IRowsetChange::InsertRow has been called. All phases can occur. |
DBREASON_ ROW_RESYNCH |
IRowsetRefresh::RefreshVisibleData has been called. All phases can occur. |
DBREASON_ ROW_UNDOCHANGE |
IRowsetUpdate::Undo has been called on a pending change row. All phases can occur. |
DBREASON_ ROW_UNDOINSERT |
IRowsetUpdate::Undo has been called on a pending insert row. All phases can occur. |
DBREASON_ ROW_UNDODELETE |
IRowsetUpdate::Undo has been called on a pending delete row. All phases can occur. |
DBREASON_ ROW_UPDATE |
IRowsetUpdate::Update has been called on a row with a pending change. All phases can occur. |
The following table lists all rowset methods, the DBREASON values they generate, and the phases for each reason. Nested notifications occur when the consumer calls another rowset method while processing a notification.
Method | DBREASON generated 1 | Phases |
IUnknown::AddRef | None | N/A |
IUnknown::QueryInterface | None | N/A |
IUnknown::Release | _ROWSET_RELEASE | DIDEVENT |
IRowset::AddRefRows | None | N/A |
IRowset::GetData | None | N/A |
IRowset::GetNextRows | _ROW_ACTIVATE | DIDEVENT |
_ROWSET_FETCHPOSITION CHANGE |
All Phases | |
IRowset::ReleaseRows | _ROW_RELEASE | DIDEVENT |
IRowset::RestartPosition | _ROWSET_FETCHPOSITION CHANGE |
All Phases |
_ROWSET_CHANGED 2 | All Phases | |
IRowsetChange::DeleteRows | _ROW_DELETE | All Phases |
IRowsetChange::InsertRow | _ROW_INSERT | All Phases |
IRowsetChange::SetData | _ROW_FIRSTCHANGE 3 | All Phases |
_COLUMN_SET | All Phases | |
_COLUMN_ RECALCULATED |
DIDEVENT | |
IRowsetIndex::Seek | _ROWSET_FETCHPOSITION CHANGE |
All Phases |
IRowsetLocate::Compare | None | N/A |
IRowsetLocate::GetRowsAt | _ROW_ACTIVATE | DIDEVENT |
IRowsetLocate:: GetRowsByBookmark |
_ROW_ACTIVATE | DIDEVENT |
IRowsetLocate::Hash | None | N/A |
IRowsetRefresh::GetLastVisibleData | None | N/A |
IRowsetRefresh::RefreshVisibleData | _ROW_RESYNCH | All Phases |
IRowsetScroll:: GetApproximatePosition |
None | N/A |
IRowsetScroll::GetRowsAtRatio | _ROW_ACTIVATE | DIDEVENT |
IRowsetUpdate::GetOriginalData | None | N/A |
IRowsetUpdate::GetPendingRows | None | N/A |
IRowsetUpdate::Undo | _ROW_UNDOCHANGE | All Phases |
_ROW_UNDOINSERT | All Phases | |
_ROW_UNDODELETE | All Phases | |
IRowsetUpdate::Update | _ROW_UPDATE | All Phases |
All other rowset methods | None | N/A |
1Methods generate only the listed DBREASON values, even though other reasons might seem appropriate. For example, InsertRow generates only DBREASON_ROW_INSERT even though DBREASON_COLUMN_SET, DBREASON_ROW_FIRSTCHANGE, and DBREASON_ROW_ACTIVATE might appear to be applicable. 2IRowset::RestartPosition generates this DBREASON only when the metadata for the columns has changed. 3DBREASON_ROW_FIRSTCHANGE is generated only the first time a column in the row is changed. For more information, see the table earlier in this section. |
Method | Description |
OnFieldChange | Notifies the consumer of any change to the value of a column. |
OnRowChange | Notifies the consumer of the first change to a row, or any change that affects the entire row. |
OnRowsetChange | Notifies the consumer of any change affecting the entire rowset. |