FIX: The Properties Collection Is Not Populated for Child Recordsets Associated with Chaptered Columns (217890)



The information in this article applies to:

  • ActiveX Data Objects (ADO) 2.1
  • ActiveX Data Objects (ADO) 2.1 SP1
  • Microsoft Data Access Components 2.1 SP2

This article was previously published under Q217890

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

This bug was corrected in MDAC 2.1 SP2.

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:

  • pADORecordset- [in] IUnknown pointer to the Ado Recordset
  • bstrPropertyName - [in] Description of the Property ID**
  • pValue - [out] The property value
** 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 that this is a bug in the Microsoft products that are listed at the beginning of this article.
This problem was corrected in MDAC 2.1 SP2.

Modification Type:MajorLast Reviewed:10/16/2002
Keywords:kbADO210sp2fix kbBug kbMDACNoSweep kbProvider KB217890