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

ID: Q217890


The information in this article applies to:
  • ActiveX Data Objects (ADO), version 2.1
  • Microsoft Data Access Components version 2.1 SP2


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:

  • 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 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,2.1 SP2
Platform : WINDOWS
Issue type : kbbug


Last Reviewed: November 8, 1999
© 2000 Microsoft Corporation. All rights reserved. Terms of Use.