BUG: The Properties Collection Is Not Populated for Child Recordsets Associated with Chaptered Columns

ID: Q217890


The information in this article applies to:


SYMPTOMS

ADO Recordset objects returned from chaptered columns do not have their Properties collection populated. The Properties collection's Count property equal zero (0).
ADO extracts a child Recordset from a Hierarchical OLEDB provider by passing the value of the chaptered column to it. In the Visual Basic client code below, "rs.Fields(5)" is the chaptered column; the variable, numProps, is zero:


Dim rs As New ADODB.Recordset
Dim rsChild As ADODB.Recordset
Dim numProps As Integer
rs.Open "c:\*.*", "Provider=ChildrsProv.CHildRSProv.1", adOpenForwardOnly, adLockOptimistic

Set rsChild = rs.Fields(5).Value
numProps = rsChild.Properties.Count 


RESOLUTION

To work around this bug, insert the following "GetProperty()" C++ function as a method in a COM object. Essentially, the function returns the requested property of the underlying rowset using the OLE DB IDBProperties::GetPropertyInfo() and IRowsetInfo::GetProperty() methods. The parameters are:

** Refer to Appendix C in the OLE DB 2.0 Programmers Reference for a comprehensive list of Property ID descriptions.

#include <COMDEF.H>
#include <oledb.h>

#undef EOF
#import "c:\program files\common files\system\ado\msado15.dll" no_namespace

_COM_SMARTPTR_TYPEDEF(IRowset, __uuidof(IRowset));
_COM_SMARTPTR_TYPEDEF(IRowsetInfo, __uuidof(IRowsetInfo));
_COM_SMARTPTR_TYPEDEF(IDBProperties, __uuidof(IDBProperties));
_COM_SMARTPTR_TYPEDEF(IGetDataSource, __uuidof(IGetDataSource));
_COM_SMARTPTR_TYPEDEF(ICommand, __uuidof(ICommand));

STDMETHODIMP CPropertyHelper::GetProperty(IUnknown *pADORecordset, BSTR bstrPropertyName, VARIANT * pValue)
{
	HRESULT hr;
	ADORecordsetConstructionPtr pRC;
	ADOConnectionConstructionPtr pCC;

	IRowsetPtr pRS;
	IRowsetInfoPtr pRI;
	IDBPropertiesPtr pDBProps;
	IGetDataSourcePtr pGetDataSource;
	ICommandPtr pCommand;
	
	// Make certain that we are getting an ADORecordset.
	pRC = pADORecordset;

	// Get the IRowsetInfo interface.
	pRI = pRC->GetRowset();

	// Get the property ID based on the name supplied.
	hr = pRI->GetSpecification(__uuidof(IGetDataSource), (IUnknown **)&pGetDataSource);

	// The rowset was probably created with IOpenRowset::OpenRowset,
	// but just in case...
	if (pGetDataSource.GetInterfacePtr() == NULL)
	{
		// Need to get command first.
		hr = pRI->GetSpecification(__uuidof(ICommand), (IUnknown **)&pCommand);
		hr = pCommand->GetDBSession(__uuidof(IGetDataSource), (IUnknown **)&pGetDataSource);
	}
		
	if(hr = pGetDataSource.GetInterfacePtr() == NULL)
		return  E_FAIL;
	hr = pGetDataSource->GetDataSource(__uuidof(IDBProperties), (IUnknown **)&pDBProps);
	// Want all of the rowset properties.
	DBPROPIDSET PropIDSet;
	PropIDSet.cPropertyIDs = 0;
	PropIDSet.guidPropertySet = DBPROPSET_ROWSETALL;
	PropIDSet.rgPropertyIDs = NULL;

	DBPROPINFOSET * pPropertyInfoSet;
	ULONG ulPropInfoSets;
	OLECHAR * pDescBuffer;
	pDBProps->GetPropertyInfo(1,&PropIDSet, &ulPropInfoSets, &pPropertyInfoSet, &pDescBuffer);
	
	DBPROPID PropID;
	GUID guid;
	bool bFoundProperty = false;
	// Find the ID associated with the property name.
	for(ULONG ulIndex1= 0; ulIndex1 < ulPropInfoSets && bFoundProperty ==false; ulIndex1 ++)
		for (ULONG ulIndex = 0; ulIndex < pPropertyInfoSet[ulIndex1].cPropertyInfos; ulIndex++)
		{
			if (_wcsicmp(pPropertyInfoSet[ulIndex1].rgPropertyInfos[ulIndex].pwszDescription, bstrPropertyName) == 0)
			{
				PropID = pPropertyInfoSet[ulIndex1].rgPropertyInfos[ulIndex].dwPropertyID;
				guid = pPropertyInfoSet[ulIndex1].guidPropertySet;
				bFoundProperty = true;
				break;
			}
	}

	// Free structures.
	CoTaskMemFree(pDescBuffer);
	CoTaskMemFree(pPropertyInfoSet->rgPropertyInfos);
	CoTaskMemFree(pPropertyInfoSet);

	if (bFoundProperty == false)
		return E_FAIL;  // Might also want to call CreateErrorInfor/SetErrorInfo.

	// Now use IRowsetInfo to return the property value.
	ULONG ulPropSets;
	DBPROPSET * prgPropSets;
	DBPROPIDSET	rgPropertyIDSets;

	rgPropertyIDSets.cPropertyIDs = 1;
	rgPropertyIDSets.guidPropertySet = guid; 
	rgPropertyIDSets.rgPropertyIDs = &PropID;

	hr = pRI->GetProperties(1, &rgPropertyIDSets, &ulPropSets, &prgPropSets);

	// Copy the property value to the return VARIANT.
	VariantCopy(pValue, &prgPropSets->rgProperties->vValue);
	CoTaskMemFree(prgPropSets->rgProperties);
	CoTaskMemFree(prgPropSets);
	
	return S_OK;
} 

The following Visual Basic code accesses the "PropertyHelper.CPropertyHelper.1" COM object that contains the GetProperty method:

Dim rs As New ADODB.Recordset
Dim rsChild As ADODB.Recordset
rs.Open "c:\*.*", "Provider=ChildrsProv.CHildRSProv.1", adOpenForwardOnly, adLockOptimistic
Set rsChild = rs.Fields(5).Value
Dim obj
Set obj = CreateObject("PropertyHelper.CPropertyHelper.1")
Dim propVal As Variant
obj.GetProperty rsChild, "IRowsetInfo", propVal
Debug.Print propVal 


STATUS

Microsoft has confirmed this to be a bug in the Microsoft products listed at the beginning of this article.

Additional query words: heirarchical


Keywords          : kbADO kbADO200bug kbATL kbDatabase kbProvider 
Version           : WINDOWS:2.1
Platform          : WINDOWS 
Issue type        : kbbug 

Last Reviewed: March 11, 1999