Memory Management

When the consumer calls a method that gets or sets data, such as IRowset::GetData, IRowsetChange::SetData, or ICommand::Execute, it passes a pointer to memory containing the data. The consumer allocates and frees this memory by the method it chooses. The provider can only read this memory. It must not free this memory, nor should it assume that this memory exists after the method returns.

If the type indicator is DBTYPE_BSTR or is combined with DBTYPE_BYREF, DBTYPE_ARRAY, or DBTYPE_VECTOR, the consumer's memory contains a pointer to other memory. The other memory actually contains the data value, as distinct from the length and status, for the column or parameter. For example, if the type indicator is DBTYPE_BYREF | DBTYPE_STR, the data value in the consumer's memory is a pointer to a string; if the type indicator is DBTYPE_BSTR, the data value is a pointer to a BSTR. The remainder of this section discusses how this other memory is managed.

Note  It could be possible for a consumer to bind an input/output parameter with a type indicator of DBTYPE_BSTR or with a type indicator that is combined with DBTYPE_BYREF, DBTYPE_ARRAY, or DBTYPE_VECTOR. In this example, when the provider returns the output value for the parameter, it overwrites the pointer in the consumer's buffer that points to the input value. To ensure access to the input value after the provider returns the output value—for example, to free it—the consumer should keep a separate copy of the pointer to the input value.

When setting data, the consumer is responsible for allocating and freeing the other memory by whatever method it chooses. The provider can only read this memory. It must not free it, nor should it assume that it exists after the method returns.

When getting data, the provider is responsible for allocating the other memory. The method by which the provider allocates this memory and the responsibility for freeing it is determined by the dwMemOwner element of the applicable binding.

If dwMemOwner is DBMEMOWNER_PROVIDEROWNED, the provider allocates the memory and frees it by whatever method it chooses. The consumer can only read the memory and must not free it or write to it. The memory is part of the rowset's copy of the row, which saves the provider from separately allocating it and the consumer from freeing it. Consumers usually use provider-owned memory when they need fast, read-only access to the data. For more information about provider-owned memory, see dwMemOwner in "DBBINDING Structures" earlier in this chapter.

If dwMemOwner is DBMEMOWNER_CLIENTOWNED, the provider allocates and the consumer frees the memory as noted below. Although the provider must not access this memory after the method returns, the consumer can access it at any time until it is freed. Consumers use consumer-owned memory when they need their own copy of the data and when they send data to the provider.

The consumer can mix bindings in which pointers to the data and the data itself are returned. For example, suppose a rowset has two columns containing ANSI strings, one of which has a maximum length of 10 characters and the other of which has a maximum length of 32,000 characters. The consumer might choose to get the first string directly in its buffer (wType is DBTYPE_STR, cbMaxLen is 11, and dwMemOwner is DBMEMOWNER_CLIENTOWNED) and get a pointer to the provider's data cache for the second string (wType is DBTYPE_STR | DBTYPE_BYREF and dwMemOwner is DBMEMOWNER_PROVIDEROWNED).

The consumer can also mix bindings in which the consumer and provider own the memory. For example, suppose a rowset contains two columns containing ANSI strings with a maximum length of 32,000 characters, but only one of which is updatable. The consumer might choose to get pointers to both strings (wType is DBTYPE_STR | DBTYPE_BYREF) but to use consumer-owned memory (dwMemOwner is DBMEMOWNER_CLIENTOWNED) for the updatable string and provider-owned memory (dwMemOwner is DBMEMOWNER_PROVIDEROWNED) for the read-only string.