Reference Accessors

A special type of accessor, called a reference accessor, enables consumers to get rowset data directly from the provider's buffer and providers to get input parameter data directly from the consumer's buffer. You cannot use these accessors with output parameters or when setting row data.

Reference accessors require the consumer to have prior knowledge of the provider's buffer layout; the consumer cannot discover this information at run time. Because of this, reference accessors are designed for use by tightly coupled consumer/provider pairs. Because they allow direct access to the provider's buffers, providers are not required to support them. Consumers determine whether providers support reference accessors through the DBPROP_BYREFACCESSORS property.

To use reference accessors, the layout of the consumer's buffer must exactly match the layout of the provider's buffer. That is, both buffers must allocate space for the same parts (data value, length, and status), these parts must appear at the same offset in both buffers, the data value parts must have the same type and buffer length in both buffers, and so on. If the provider's buffer does not contain length or status parts, the consumer cannot bind these parts, and must determine length and whether the data value is NULL in the same manner as the provider.

To use a reference accessor, the consumer passes the handle of the accessor and a pointer to a buffer to the provider. For rowset data, the provider returns a pointer to its internal buffer in the buffer supplied by the consumer. The consumer then dereferences this pointer and reads directly from the provider's buffer. For input parameter data, the consumer's buffer contains a pointer to the buffer that actually contains the data. The provider dereferences this pointer and reads directly from the consumer's other buffer.

For example, the following code shows how a consumer would read data directly from the provider's buffer using a reference accessor:

  1. Assume that the consumer already has a pointer to IAccessor on a rowset (pIAccessor) and a pointer to IRowset on the same rowset (pIRowset).
    void *  pv;
    ULONG   cRowsObtained;
    HACCESSOR hReferenceAccessor;
    HROW  rghRows[1];
    DBBINDING rgBindings[5];

  1. Fill in the rgBinding array. The bindings must match the layout of the provider's buffer.

  2. Create a reference accessor.
    pIAccessor->CreateAccessor(DBACCESSOR_ROWDATA | DBACCESSOR_PASSBYREF, 5, rgBindings, 0, &hReferenceAccessor, NULL);

  1. Get a row.
    pIRowset->GetNextRows(NULL, 0, 1, &cRowsObtained, rghRows);

  1. Get a pointer to the start of the provider's buffer for the row.
    pIRowset->GetData(rghRows[0], hReferenceAccessor, &pv);

  1. Access the data in the provider's buffer, starting at the address *pv. (Code not shown.)

The pointer returned by the provider, for rowset data, or passed by the consumer, for input parameter data, does not need to point to the start of the buffer. The only requirement is that the relative offsets of the elements stored in the buffer match the offsets specified in the accessor. The consumer, for rowset data, or provider, for input parameter data, must not write to this buffer, nor can it free this buffer.

For rowset data, the pointer is guaranteed to remain valid until the consumer calls IRowsetChange::SetData, IRowsetChange::DeleteRows, IRowsetRefresh::RefreshVisibleData, IRowsetUpdate::Undo, or IRowsetUpdate::Update for the row, calls IRowset::ReleaseRows for the row and the reference count falls to zero, or releases the rowset. For input parameter data, the pointer is guaranteed to remain valid only until ICommand::Execute returns.