//--------------------------------------------------------------------
// Microsoft OLE DB Test
//
// Copyright (C) 1995-2000 Microsoft Corporation
//
// @doc
//
// @module IRow.cpp | This module tests the OLEDB IRow interface
//

#include "MODStandard.hpp"		// Standard headers
#include "IRow.h"				// IRow header
#include "ExtraLib.h"

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Module Values
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

// {{ TCW_MODULE_GLOBALS
DECLARE_MODULE_CLSID = { 0xf61ea340, 0x2b1e, 0x11d2, { 0xa9, 0x8d, 0x00, 0xc0, 0x4f, 0x94, 0xa7, 0x17} };
DECLARE_MODULE_NAME("IRow");
DECLARE_MODULE_OWNER("Microsoft");
DECLARE_MODULE_DESCRIP("IRow interface test");
DECLARE_MODULE_VERSION(838086926);
// TCW_WizardVersion(2)
// TCW_Automation(False)
// }} TCW_MODULE_GLOBALS_END

//////////////////////////////////////////////////////////////////////////
// Globals
//
//////////////////////////////////////////////////////////////////////////
ULONG cInterfaceIIDs = 0;
INTERFACEMAP* rgInterfaceIIDs = NULL;

//--------------------------------------------------------------------
// @func Module level initialization routine
//
// @rdesc Success or Failure
// 		@flag  TRUE  | Successful initialization
//		@flag  FALSE | Initialization problems
//
BOOL ModuleInit(CThisTestModule * pThisTestModule)
{
	//Obtain the Interface IIDs for the Row object
	//NOTE: I need at least as many rows as columns so cover the case of the BLOB columns being NULL...

	if(GetInterfaceArray(ROW_INTERFACE, &cInterfaceIIDs, &rgInterfaceIIDs))
		return CommonModuleInit(pThisTestModule, IID_IRow, max(25,SIZEOF_TABLE), ROW_INTERFACE);

	return FALSE;
}

//--------------------------------------------------------------------
// @func Module level termination routine
//
// @rdesc Success or Failure
// 		@flag  TRUE  | Successful initialization
//		@flag  FALSE | Initialization problems
//
BOOL ModuleTerminate(CThisTestModule * pThisTestModule)
{
    return CommonModuleTerminate(pThisTestModule);
}

////////////////////////////////////////////////////////////////////////////
//  TCIRow
//
////////////////////////////////////////////////////////////////////////////
class TCIRow : public CRowset
{
public:
	//constructors
	TCIRow(WCHAR* pwszTestCaseName = INVALID(WCHAR*));
	virtual ~TCIRow();

	//methods
	virtual BOOL		Init();
	virtual BOOL		Terminate();

	//IRow
	virtual BOOL		VerifyGetColumns
						(
							CRowObject*			pCRowObject,
							DBCOUNTITEM			iRow,
							ECOLS_BOUND			eColsToBind		= ALL_COLS_BOUND,
							BLOBTYPE			dwBlobType		= NO_BLOB_COLS,
							ECOLUMNORDER		eBindingOrder	= FORWARD,
							ECOLS_BY_REF		eColsByRef		= NO_COLS_BY_REF,
							DBTYPE				dwModifier		= DBTYPE_EMPTY,
							DBORDINAL				cColsToBind		= 0,
							DBORDINAL*				rgColsToBind    = NULL,
							DBPART				dwPart			= DBPART_VALUE|DBPART_LENGTH|DBPART_STATUS
						);

	virtual BOOL		VerifyGetColumnsAllRows
						(
							CRowset*			pCRowset,
							ECOLS_BOUND			eColsToBind		= ALL_COLS_BOUND,
							BLOBTYPE			dwBlobType		= NO_BLOB_COLS,
							ECOLUMNORDER		eBindingOrder	= FORWARD,
							ECOLS_BY_REF		eColsByRef		= NO_COLS_BY_REF,
							DBTYPE				dwModifier		= DBTYPE_EMPTY,
							DBORDINAL				cColsToBind		= 0,
							DBORDINAL*				rgColsToBind    = NULL,
							DBPART				dwPart			= DBPART_VALUE|DBPART_LENGTH|DBPART_STATUS
						);

	virtual BOOL		VerifyGetSourceRowset
						(
							REFIID riid,
							IUnknown** ppIRowset = NULL,
							HROW* phRow = NULL
						);

	virtual HRESULT		FindObject
						(
							CRowObject*		pCRowObject,
							IUnknown*		pUnkOuter,
							REFGUID			rguid,
							REFIID			riid,
							IUnknown**		ppIUnknown,
							DBID**			ppColumnID
						);

	virtual BOOL		VerifyOpenAllColumns
						(
							IUnknown*			pIUnkOuter,
							CRowObject*			pCRowObject,
							DBCOUNTITEM				iRow,
							REFGUID				rGuidType,
							REFIID				riid			= IID_IUnknown,
							ECOLS_BOUND			eColsToBind		= ALL_COLS_BOUND,
							BLOBTYPE			dwBlobType		= BLOB_LONG,
							ECOLUMNORDER		eBindingOrder	= FORWARD,
							ECOLS_BY_REF		eColsByRef		= NO_COLS_BY_REF,
							DBTYPE				dwModifier		= DBTYPE_EMPTY,
							DBORDINAL				cColsToBind		= 0,
							DBORDINAL*				rgColsToBind    = NULL
						);

	virtual BOOL		VerifyOpenAllRows
						(
							CRowset*			pCRowset,
							REFGUID				rGuidType,
							REFIID				riid			= IID_IUnknown,
							ECOLS_BOUND			eColsToBind		= ALL_COLS_BOUND,
							BLOBTYPE			dwBlobType		= BLOB_LONG,
							ECOLUMNORDER		eBindingOrder	= FORWARD,
							ECOLS_BY_REF		eColsByRef		= NO_COLS_BY_REF,
							DBTYPE				dwModifier		= DBTYPE_EMPTY,
							DBORDINAL				cColsToBind		= 0,
							DBORDINAL*				rgColsToBind    = NULL
						);

	virtual BOOL		VerifyOpenAllInterfaces
						(
							EINTERFACE eInterface,
							REFGUID rGuidType
						);

	virtual BOOL		VerifyOpenWithOpenObjects
						(
							REFGUID rGuidtype,
							REFIID riid
						);

	virtual BOOL		VerifyOpenWithOpenObjects
						(
							REFGUID rGuidtype,
							REFIID riid,
							CRowObject *pRowObjects,
							DWORD *pThreadIDs,
							bool fDifferentColumns
						);

	//Thread Methods
	static ULONG WINAPI Thread_VerifyGetColumns(LPVOID pv);
	static ULONG WINAPI Thread_VerifyGetSourceRowset(LPVOID pv);
	static ULONG WINAPI Thread_VerifyOpenWithOpenObjects(LPVOID pv);

	//Interface

	//Data
	CRowObject*			m_pCRowObject;
};

////////////////////////////////////////////////////////////////////////////
//  TCIRow::TCIRow
//
////////////////////////////////////////////////////////////////////////////
TCIRow::TCIRow(WCHAR * wstrTestCaseName)	: CRowset(wstrTestCaseName)
{
	m_pCRowObject	= NULL;
}

////////////////////////////////////////////////////////////////////////////
//  TCIRow::~TCIRow
//
////////////////////////////////////////////////////////////////////////////
TCIRow::~TCIRow()
{
}

////////////////////////////////////////////////////////////////////////////
//  TCIRow::Init
//
////////////////////////////////////////////////////////////////////////////
BOOL TCIRow::Init()
{
	TBEGIN
	HRESULT hr = S_OK;

	//Create the new row object
	m_pCRowObject = new CRowObject;
	TESTC(m_pCRowObject != NULL);
	TESTC(CRowset::Init());

	//May require AccessOrder to position on Blobs
//	SetSettableProperty(DBPROP_IRowsetLocate, DBPROPSET_ROWSET, (void*)VARIANT_TRUE, DBTYPE_BOOL);
	SetSettableProperty(DBPROP_ACCESSORDER, DBPROPSET_ROWSET, (void*)DBPROPVAL_AO_RANDOM, DBTYPE_I4);

	//CANHOLDROWS is a required property
	//We need this since we create 1 rowset, but each variation obtains rows from different positions
	//many times restarting to obtain a previous row...
	SetProperty(DBPROP_CANHOLDROWS);

	//Create the Rowset object
	TESTC_(CreateRowset(SELECT_ORDERBYNUMERIC), S_OK);

	//Obtain the first row object
	TESTC_(GetRowObject(FIRST_ROW, m_pCRowObject),S_OK);

CLEANUP:
	TRETURN
}

////////////////////////////////////////////////////////////////////////////
//  TCIRow::Terminate
//
////////////////////////////////////////////////////////////////////////////
BOOL TCIRow::Terminate()
{
	SAFE_DELETE(m_pCRowObject);
	return CRowset::Terminate();
}

////////////////////////////////////////////////////////////////////////////
//  TCIRow::VerifyGetColumns
//
////////////////////////////////////////////////////////////////////////////
BOOL TCIRow::VerifyGetColumns
(
	CRowObject*			pCRowObject,
	DBCOUNTITEM				iRow,
	ECOLS_BOUND			eColsToBind,
	BLOBTYPE			dwBlobType,
	ECOLUMNORDER		eBindingOrder,
	ECOLS_BY_REF		eColsByRef,
	DBTYPE				dwModifier,
	DBORDINAL				cColsToBind,
	DBORDINAL*				rgColsToBind,
	DBPART				dwPart
)
{
	//Delegate
	return pCRowObject->VerifyGetColumns(iRow, pTable(), eColsToBind, dwBlobType, eBindingOrder, eColsByRef, dwModifier, cColsToBind, rgColsToBind, dwPart);
}

////////////////////////////////////////////////////////////////////////////
//  TCIRow::VerifyGetColumnsAllRows
//
////////////////////////////////////////////////////////////////////////////
BOOL TCIRow::VerifyGetColumnsAllRows
(
	CRowset*			pCRowset,
	ECOLS_BOUND			eColsToBind,
	BLOBTYPE			dwBlobType,
	ECOLUMNORDER		eBindingOrder,
	ECOLS_BY_REF		eColsByRef,
	DBTYPE				dwModifier,
	DBORDINAL				cColsToBind,
	DBORDINAL*				rgColsToBind,
	DBPART				dwPart
)
{
	TBEGIN
	HRESULT hr = S_OK;

	DBCOUNTITEM iRow,cRowsObtained = 0;
	HROW hRow = NULL;
	CRowset RowsetA;

	//Default rowset
	if(pCRowset == NULL)
	{
		pCRowset = &RowsetA;

		//May require AccessOrder to position on Blobs
		if(dwBlobType != NO_BLOB_COLS)
			pCRowset->SetSettableProperty(DBPROP_ACCESSORDER, DBPROPSET_ROWSET, (void*)DBPROPVAL_AO_RANDOM, DBTYPE_I4);
		TESTC_(pCRowset->CreateRowset(),S_OK);
	}

	//Restart the position.
	TESTC_(pCRowset->RestartPosition(),S_OK);

	//loop through the rowset, retrieve one row at a time
	for(iRow=1; iRow<=pCRowset->m_ulTableRows; iRow++)
	{
		//GetNextRow
		CRowObject RowObjectA;
		TESTC_(pCRowset->GetNextRows(&hRow),S_OK);

		//Create the row object from this row
		TESTC_(pCRowset->GetRowObject(iRow, &RowObjectA, 0, hRow), S_OK);

		//Verify Row Object
		if(!VerifyGetColumns(&RowObjectA, iRow, eColsToBind, dwBlobType, eBindingOrder, eColsByRef, dwModifier, cColsToBind, rgColsToBind, dwPart))
		{
			//Data incorrect for this row!
			TERROR("Data was incorrect for row " << iRow);
			QTESTC(FALSE);
		}

		//release the row handle
		TESTC_(pCRowset->ReleaseRows(hRow),S_OK);
	}

CLEANUP:
	RowsetA.ReleaseRows(hRow);
	TRETURN
}

///////////////////////////////////////////////////////////////////////////
//  TCIRow::VerifyGetSourceRowset
//
////////////////////////////////////////////////////////////////////////////
BOOL TCIRow::VerifyGetSourceRowset
(
	REFIID riid,
	IUnknown** ppIRowset,
	HROW* phRow
)
{
	TBEGIN
	HRESULT hr = S_OK;
	IUnknown* pIUnknown = NULL;
	HROW hRow = NULL;

	//IRow::GetSourceRowset...
	//NOTE: Verification is done in the helper
	TEST2C_(hr = m_pCRowObject->GetSourceRowset(riid, &pIUnknown, &hRow),S_OK,DB_E_NOSOURCEOBJECT);

CLEANUP:
	if(ppIRowset)
		*ppIRowset = pIUnknown;
	else
		SAFE_RELEASE(pIUnknown);
	if(phRow)
		*phRow = hRow;
	else
		ReleaseRows(hRow);
	TRETURN
}

///////////////////////////////////////////////////////////////////////////
//  TCIRow::VerifyOpenAllColumns
//
////////////////////////////////////////////////////////////////////////////
BOOL TCIRow::VerifyOpenAllColumns
(
	IUnknown*			pIUnkOuter,
	CRowObject*			pCRowObject,
	DBCOUNTITEM			iRow,
	REFGUID				rGuidType,
	REFIID				riid,
	ECOLS_BOUND			eColsToBind,
	BLOBTYPE			dwBlobType,
	ECOLUMNORDER		eBindingOrder,
	ECOLS_BY_REF		eColsByRef,
	DBTYPE				dwModifier,
	DBORDINAL				cColsToBind,
	DBORDINAL*				rgColsToBind
)
{
	TBEGIN
	ASSERT(pCRowObject);
	HRESULT hr = S_OK;
	DBORDINAL i,cColAccess = 0;
	DBCOLUMNACCESS* rgColAccess = NULL;
	void* pData = NULL;

	//Create the ColAccess Structures...
	TESTC_(hr = pCRowObject->CreateColAccess(&cColAccess, &rgColAccess, &pData, NULL, eColsToBind, dwBlobType, eBindingOrder, eColsByRef, dwModifier, cColsToBind, rgColsToBind),S_OK);

	//IRow::Open (for all bound columns)
	for(i=0; i<cColAccess; i++)
	{
		//Open wil mainly only be able to be called for columns containing objects.
		//But some providers might be able to open streams, or other types of objects ontop
		//of non-object valued columns.
		hr = pCRowObject->VerifyOpen(iRow, pTable(), pIUnkOuter, &rgColAccess[i].columnid, rGuidType, riid);
		TEST4C_(hr, S_OK, DB_E_NOTFOUND, DB_E_OBJECTMISMATCH, E_NOINTERFACE);

		//Produce a error if this was an IUnknown column and it could not be opened...
		//At the very least a consumer should be able to open the column as the default
		//native object type (GUID_NULL, and IID_IUnknown)
		if(FAILED(hr))
		{
			if(rgColAccess[i].wType==DBTYPE_IUNKNOWN && rGuidType == GUID_NULL && riid == IID_IUnknown)
				TOUTPUT("WARNING:  IUnknown column unable to be opened with IRow::Open(GUID_NULL, IID_IUnknown...)?");
		}
	}

	//DBROWCOL_DEFAULTSTREAM
	//Now that we have done the returned columns, lets also see if there is a default stream object.
	TEST4C_(hr = pCRowObject->Open(pIUnkOuter, &DBROWCOL_DEFAULTSTREAM, DBGUID_STREAM, IID_IStream), S_OK, DB_E_NOTFOUND, DB_E_BADCOLUMNID, DB_E_NOAGGREGATION);

	//Only Allow no aggregation if using a controlling unknown
	if(hr == DB_E_NOAGGREGATION)
		TESTC(pIUnkOuter != NULL);

CLEANUP:
	FreeColAccess(cColAccess, rgColAccess);
	SAFE_FREE(pData);
	TRETURN
}

////////////////////////////////////////////////////////////////////////////
//  TCIRow::VerifyOpenAllRows
//
////////////////////////////////////////////////////////////////////////////
BOOL TCIRow::VerifyOpenAllRows
(
	CRowset*			pCRowset,
	REFGUID				rGuidType,
	REFIID				riid,
	ECOLS_BOUND			eColsToBind,
	BLOBTYPE			dwBlobType,
	ECOLUMNORDER		eBindingOrder,
	ECOLS_BY_REF		eColsByRef,
	DBTYPE				dwModifier,
	DBORDINAL				cColsToBind,
	DBORDINAL*				rgColsToBind
)
{
	TBEGIN
	HRESULT hr = S_OK;
	CRowset RowsetA;
	HROW hRow = NULL;
	DBCOUNTITEM iRow = 0;

	//Default rowset
	if(pCRowset == NULL)
	{
		pCRowset = &RowsetA;
		TESTC_(pCRowset->CreateRowset(),S_OK);
	}

	//loop through the rowset, retrieve one row at a time
	for(iRow=1; iRow<=pCRowset->m_ulTableRows; iRow++)
	{
		//GetNextRow
		CRowObject RowObjectA;
		TESTC_(pCRowset->GetNextRows(&hRow),S_OK);

		//Create the row object from this row
		TESTC_(pCRowset->GetRowObject(iRow, &RowObjectA, 0, hRow),S_OK);

		//Verify Row Object
		TESTC(VerifyOpenAllColumns(NULL, &RowObjectA, iRow, rGuidType, riid, eColsToBind, dwBlobType, eBindingOrder, eColsByRef, dwModifier, cColsToBind, rgColsToBind));

		//release the row handle
		TESTC_(pCRowset->ReleaseRows(hRow),S_OK);
	}

CLEANUP:
	pCRowset->ReleaseRows(hRow);
	TRETURN
}

////////////////////////////////////////////////////////////////////////////
//  TCIRow::VerifyOpenAllInterfaces
//
////////////////////////////////////////////////////////////////////////////
BOOL TCIRow::VerifyOpenAllInterfaces(EINTERFACE eInterface, REFGUID rGuidType)
{
	TBEGIN
	HRESULT hr = S_OK;

	//Obtain the Rowset interfaces...
	ULONG iCol,cIIDs = 0;
	INTERFACEMAP* rgIIDs = NULL;
	GetInterfaceArray(eInterface, &cIIDs, &rgIIDs);

	//Obtain the row object
	CRowObject RowObjectA;
	TESTC_(GetRowObject(FIRST_ROW, &RowObjectA), S_OK);

	//Loop through all the columns...
	for(iCol=0; iCol<RowObjectA.m_cColAccess; iCol++)
	{
		//For every [MANDATORY] interface
		for(ULONG iInterface=0; iInterface<cIIDs; iInterface++)
		{
			//IRow::Open
			//All interface testing is done with the IRow::Open helper...
			hr = RowObjectA.Open(NULL, &RowObjectA.m_rgColAccess[iCol].columnid, rGuidType, *rgIIDs[iInterface].pIID);

			//Determine results
			if(rgIIDs[iInterface].fMandatory)
			{
				//[MANDATORY]
				if(hr!=S_OK && hr!=DB_E_NOTFOUND && hr!=DB_E_OBJECTMISMATCH)
				{
					TERROR(L"Interface Incorrect for " << GetInterfaceName(*rgIIDs[iInterface].pIID));
					CHECK(hr, S_OK);
				}
			}
			else
			{
				//[OPTIONAL]
				if(hr!=S_OK && hr!=DB_E_NOTFOUND && hr!=DB_E_OBJECTMISMATCH && hr!=E_NOINTERFACE)
				{
					TERROR(L"Interface Incorrect for " << GetInterfaceName(*rgIIDs[iInterface].pIID));
					CHECK(hr, S_OK);
				}
			}
		}
	}

CLEANUP:
	TRETURN
}

////////////////////////////////////////////////////////////////////////////
//  TCIRow::VerifyOpenWithOpenObjects
//
////////////////////////////////////////////////////////////////////////////
BOOL TCIRow::VerifyOpenWithOpenObjects(REFGUID rGuidType, REFIID riid)
{
	TBEGIN
	IUnknown* pIUnknown = NULL;
	IUnknown* pIUnknown2 = NULL;
	IUnknown* pIRowset = NULL;
	IUnknown* pIRowset2 = NULL;
	ULONG iCol = 0;

	//Obtain the row object
	CRowObject RowObjectA;
	TESTC_(GetRowObject(FIRST_ROW, &RowObjectA), S_OK);

	//Loop through all the columns...
	for(iCol=0; iCol<RowObjectA.m_cColAccess; iCol++)
	{
		DBCOLUMNACCESS* pColAccess = &RowObjectA.m_rgColAccess[iCol];
		DBID* pColumnID = &pColAccess->columnid;

		//Open the column as a stream object (and keep it open)
		HRESULT hr = RowObjectA.VerifyOpen(FIRST_ROW, pTable(), NULL, pColumnID, rGuidType, riid, &pIUnknown);
		TEST4C_(hr, S_OK, DB_E_NOTFOUND, DB_E_OBJECTMISMATCH, E_NOINTERFACE);
		if(hr==S_OK)
		{
			if(rGuidType == DBGUID_STREAM)
			{
				//The helper already read and verified the stream...
			}
			else if(rGuidType == DBGUID_ROW)
			{
				//GetSourceRowset
				ASSERT(riid == IID_IRow);
				TEST2C_(((IRow*)pIUnknown)->GetSourceRowset(IID_IRowset, &pIRowset, NULL),S_OK,DB_E_NOSOURCEOBJECT);
			}

			//Try Opening the Object again
			hr = RowObjectA.VerifyOpen(FIRST_ROW, pTable(), NULL, pColumnID, rGuidType, riid, &pIUnknown2);
			TEST5C_(hr, S_OK, DB_E_NOTFOUND, DB_E_OBJECTMISMATCH, DB_E_OBJECTOPEN, E_NOINTERFACE);
			if(hr==S_OK)
			{
				if(rGuidType == DBGUID_STREAM)
				{
					//The helper already read and verified the stream...
				}
				else if(rGuidType == DBGUID_ROW)
				{
					//GetSourceRowset
					ASSERT(riid == IID_IRow);
					TEST2C_(((IRow*)pIUnknown)->GetSourceRowset(IID_IRowset, &pIRowset2, NULL),S_OK,DB_E_NOSOURCEOBJECT);
					if(pIRowset && pIRowset2)
						TESTC(VerifyEqualInterface(pIRowset, pIRowset2));
				}
			}
		}

		if(FAILED(hr) && hr!=DB_E_OBJECTOPEN)
		{
			//Produce a error if this was an IUnknown column and it could not be opened...
			//At the very least a consumer should be able to open the column as the default
			//native object type (GUID_NULL, and IID_IUnknown)
			if(pColAccess->wType==DBTYPE_IUNKNOWN && rGuidType == GUID_NULL && riid == IID_IUnknown)
				TOUTPUT("WARNING:  IUnknown column unable to be opened with IRow::Open(GUID_NULL, IID_IUnknown...)?");
		}

		//Release all Objects
		SAFE_RELEASE(pIUnknown);
		SAFE_RELEASE(pIUnknown2);
		SAFE_RELEASE(pIRowset);
		SAFE_RELEASE(pIRowset2);
	}

CLEANUP:
	//Release all Objects
	SAFE_RELEASE(pIUnknown);
	SAFE_RELEASE(pIUnknown2);
	SAFE_RELEASE(pIRowset);
	SAFE_RELEASE(pIRowset2);
	TRETURN
}

////////////////////////////////////////////////////////////////////////////
//  Version of TCIRow::VerifyOpenWithOpenObjects with minimized privlib
//  code usage, to avoid multithreading issues
////////////////////////////////////////////////////////////////////////////
BOOL TCIRow::VerifyOpenWithOpenObjects(
	REFGUID rGuidType,
	REFIID riid,
	CRowObject *pRowObjects,
	DWORD *pThreadIDs,
	bool fDifferentColumns)
{
	TBEGIN
	IUnknown* pIUnknown = NULL;
	IUnknown* pIUnknown2 = NULL;
	IUnknown* pIRowset = NULL;
	IUnknown* pIRowset2 = NULL;
	ULONG iCol = 0;

	//lookup the row object
	DWORD dwCurrentThreadID = GetCurrentThreadId();
	CRowObject *pRowObject;
	for (int i = 0; ; ++i)
	{
		if (pThreadIDs[i] == dwCurrentThreadID)
		{
			pRowObject = pRowObjects + i;
			break;
		}
	}

	//Loop through all the columns...
	for(iCol=0; iCol<pRowObject->m_cColAccess; iCol++)
	{
		DBCOLUMNACCESS* pColAccess = &pRowObject->m_rgColAccess[iCol]; //need only columnid and wType
		DBID* pColumnID = &pColAccess->columnid;

		// do several iterations over same column
		for (DBORDINAL iteration = 0; iteration < 10; ++iteration)
		{
			//Open the column as a stream object (and keep it open)
			HRESULT hr = pRowObject->VerifyOpen(FIRST_ROW, pTable(), NULL, pColumnID, rGuidType, riid, &pIUnknown);
			//Depending upon thread timing we may encounter an open object
			TEST5C_(hr, S_OK, DB_E_NOTFOUND, DB_E_OBJECTMISMATCH, E_NOINTERFACE,DB_E_OBJECTOPEN);
			if(hr==S_OK)
			{
				if(rGuidType == DBGUID_STREAM)
				{
					//The helper already read and verified the stream...
				}
				else if(rGuidType == DBGUID_ROW)
				{
					//GetSourceRowset
					ASSERT(riid == IID_IRow);
					TEST2C_(((IRow*)pIUnknown)->GetSourceRowset(IID_IRowset, &pIRowset, NULL),S_OK,DB_E_NOSOURCEOBJECT);
				}

				//Try Opening the Object again
				hr = pRowObject->VerifyOpen(FIRST_ROW, pTable(), NULL, pColumnID, rGuidType, riid, &pIUnknown2);
				TEST5C_(hr, S_OK, DB_E_NOTFOUND, DB_E_OBJECTMISMATCH, DB_E_OBJECTOPEN, E_NOINTERFACE);
				if(hr==S_OK)
				{
					if(rGuidType == DBGUID_STREAM)
					{
						//The helper already read and verified the stream...
					}
					else if(rGuidType == DBGUID_ROW)
					{
						//GetSourceRowset
						ASSERT(riid == IID_IRow);
						TEST2C_(((IRow*)pIUnknown)->GetSourceRowset(IID_IRowset, &pIRowset2, NULL),S_OK,DB_E_NOSOURCEOBJECT);
						if(pIRowset && pIRowset2)
							TESTC(VerifyEqualInterface(pIRowset, pIRowset2));
					}
				}
			}

			if(FAILED(hr) && hr!=DB_E_OBJECTOPEN)
			{
				//Produce a error if this was an IUnknown column and it could not be opened...
				//At the very least a consumer should be able to open the column as the default
				//native object type (GUID_NULL, and IID_IUnknown)
				if(pColAccess->wType==DBTYPE_IUNKNOWN && rGuidType == GUID_NULL && riid == IID_IUnknown)
					TOUTPUT("WARNING:  IUnknown column unable to be opened with IRow::Open(GUID_NULL, IID_IUnknown...)?");
			}

			//Release all Objects
			SAFE_RELEASE(pIUnknown);
			SAFE_RELEASE(pIUnknown2);
			SAFE_RELEASE(pIRowset);
			SAFE_RELEASE(pIRowset2);

			if (fDifferentColumns)
			{
				// no need to do several iterations over the same column, proceed to the next one
				break;
			}
		}
	}

CLEANUP:
	//Release all Objects
	SAFE_RELEASE(pIUnknown);
	SAFE_RELEASE(pIUnknown2);
	SAFE_RELEASE(pIRowset);
	SAFE_RELEASE(pIRowset2);
	TRETURN
}

///////////////////////////////////////////////////////////////////////////
//  TCIRow::FindObject
//
////////////////////////////////////////////////////////////////////////////
HRESULT TCIRow::FindObject
(
	CRowObject*		pCRowObject,
	IUnknown*		pUnkOuter,
	REFGUID			rguid,
	REFIID			riid,
	IUnknown**		ppIUnknown,
	DBID**			ppColumnID
)
{
	TBEGIN
	ASSERT(pCRowObject);
	ASSERT(ppIUnknown);
	HRESULT hr = S_OK;
	DBORDINAL i,cColAccess = 0;
	DBCOLUMNACCESS* rgColAccess = NULL;
	void* pData = NULL;

	if(ppColumnID)
		*ppColumnID = NULL;

	//Create the ColAccess Structures...
	TESTC_(hr = pCRowObject->CreateColAccess(&cColAccess, &rgColAccess, &pData, NULL, ALL_COLS_BOUND, BLOB_LONG),S_OK);

	//Try to find an object of the specified type...
	for(i=0; i<cColAccess; i++)
	{
		//Delegate
		//NOTE: The healper verifies everything, we just need an object...
		hr = pCRowObject->Open(pUnkOuter, &rgColAccess[i].columnid, rguid, riid, ppIUnknown);

		//Did we find one yet?
		if(SUCCEEDED(hr))
		{
			if(ppColumnID)
			{
				SAFE_ALLOC(*ppColumnID, DBID, 1);
				TESTC_(hr = DuplicateDBID(rgColAccess[i].columnid, *ppColumnID),S_OK);
			}
			break;
		}
	}

CLEANUP:
	FreeColAccess(cColAccess, rgColAccess);
	SAFE_FREE(pData);
	return hr;
}

////////////////////////////////////////////////////////////////////////////
//  TCIRow::Thread_VerifyGetColumns
//
////////////////////////////////////////////////////////////////////////////
ULONG TCIRow::Thread_VerifyGetColumns(void* pv)
{
	THREAD_BEGIN

	//Thread Stack Variables
	TCIRow* pThis =				(TCIRow*)THREAD_FUNC;
	CRowObject* pCRowObject =	(CRowObject*)THREAD_ARG1;
	ASSERT(pThis);

	ThreadSwitch(); //Let the other thread(s) catch up

	//IRow::GetColumns
	TESTC(pThis->VerifyGetColumns(pCRowObject, FIRST_ROW, ALL_COLS_BOUND));

	ThreadSwitch(); //Let the other thread(s) catch up

CLEANUP:
	THREAD_RETURN
}

////////////////////////////////////////////////////////////////////////////
//  TCIRow::Thread_VerifyGetSourceRowset
//
////////////////////////////////////////////////////////////////////////////
ULONG TCIRow::Thread_VerifyGetSourceRowset(void* pv)
{
	THREAD_BEGIN

	//Thread Stack Variables
	TCIRow* pThis = (TCIRow*)THREAD_FUNC;
	ASSERT(pThis);

	ThreadSwitch(); //Let the other thread(s) catch up

	//IRow::GetColumns
	TESTC(pThis->VerifyGetSourceRowset(IID_IRowset));

	ThreadSwitch(); //Let the other thread(s) catch up

CLEANUP:
	THREAD_RETURN
}

////////////////////////////////////////////////////////////////////////////
//  TCIRow::Thread_VerifyOpenWithOpenObjects
//
////////////////////////////////////////////////////////////////////////////
ULONG TCIRow::Thread_VerifyOpenWithOpenObjects(void* pv)
{
	THREAD_BEGIN

	//Thread Stack Variables
	TCIRow* pThis		= (TCIRow*)THREAD_FUNC;
	GUID	rGuidType	= *(GUID*)THREAD_ARG1;
	IID		riid		= *(IID*)THREAD_ARG2;
	CRowObject *pRowObjects = (CRowObject*)THREAD_ARG3;
	DWORD	   *pThreadIDs  = (DWORD*)THREAD_ARG4;
	bool fDifferentColumns = *(bool*)THREAD_ARG5;
	ASSERT(pThis);

	ThreadSwitch(); //Let the other thread(s) catch up

	//IRow::Open
	TESTC(pThis->VerifyOpenWithOpenObjects(rGuidType, riid, pRowObjects, pThreadIDs, fDifferentColumns));

	ThreadSwitch(); //Let the other thread(s) catch up

CLEANUP:
	THREAD_RETURN
}

// {{ TCW_TEST_CASE_MAP(TCIRow_IUnknown)
//*-----------------------------------------------------------------------
// @class IRow IUnknown scenarios
//
class TCIRow_IUnknown : public TCIRow {
private:
	// @cmember Static array of variations
	DECLARE_TEST_CASE_DATA();

public:
	// {{ TCW_DECLARE_FUNCS
	// @cmember Execution Routine
	DECLARE_TEST_CASE_FUNCS(TCIRow_IUnknown,TCIRow);
	// }} TCW_DECLARE_FUNCS_END

	// @cmember Initialization Routine
	virtual BOOL Init();
	// @cmember Termination Routine
	virtual BOOL Terminate();

	// {{ TCW_TESTVARS()
	// @cmember IUnknown - QI Mandatory Interfaces
	int Variation_1();
	// @cmember IUnknown - QI Optional Interfaces
	int Variation_2();
	// @cmember IUnknown - AddRef / Release
	int Variation_3();
	// }} TCW_TESTVARS_END
} ;
// {{ TCW_TESTCASE(TCIRow_IUnknown)
#define THE_CLASS TCIRow_IUnknown
BEG_TEST_CASE(TCIRow_IUnknown, TCIRow, L"IRow IUnknown scenarios")
	TEST_VARIATION(1, 		L"IUnknown - QI Mandatory Interfaces")
	TEST_VARIATION(2, 		L"IUnknown - QI Optional Interfaces")
	TEST_VARIATION(3, 		L"IUnknown - AddRef / Release")
END_TEST_CASE()
#undef THE_CLASS
// }} TCW_TESTCASE_END
// }} TCW_TEST_CASE_MAP_END

// {{ TCW_TEST_CASE_MAP(TCIRow_GetColumns)
//*-----------------------------------------------------------------------
// @class IRow::GetColumns
//
class TCIRow_GetColumns : public TCIRow {
private:
	// @cmember Static array of variations
	DECLARE_TEST_CASE_DATA();

public:
	// {{ TCW_DECLARE_FUNCS
	// @cmember Execution Routine
	DECLARE_TEST_CASE_FUNCS(TCIRow_GetColumns,TCIRow);
	// }} TCW_DECLARE_FUNCS_END

	// @cmember Initialization Routine
	virtual BOOL Init();
	// @cmember Termination Routine
	virtual BOOL Terminate();

	BOOL FindColumnDBTYPE_BYTES(DBSTATUS status, DBCOUNTITEM *pRowIndex, DBORDINAL *pColIndex);
	int UnalignedBuferTest(DBSTATUS columnStatus);

	// {{ TCW_TESTVARS()
	// @cmember GetColumns - All columns - no BLOBs
	int Variation_1();
	// @cmember GetColumns - All Columns - BLOBs
	int Variation_2();
	// @cmember GetColumns - same column bound numerous times
	int Variation_3();
	// @cmember GetColumns - BLOB Columns only
	int Variation_4();
	// @cmember GetColumns - Each Column Seperatly
	int Variation_5();
	// @cmember GetColumns - Asking for just Rowset columns
	int Variation_6();
	// @cmember GetColumns - Asking for just Extra Row Columns
	int Variation_7();
	// @cmember GetColumns - IUnknown Columns - native
	int Variation_8();
	// @cmember Empty
	int Variation_9();
	// @cmember GetColumns - Not Binding Value, pData is NULL
	int Variation_10();
	// @cmember GetColumns - Value not bound for some columns
	int Variation_11();
	// @cmember Empty
	int Variation_12();
	// @cmember Vectors - Some valid, some non-existent columns - DB_S_ERRORSOCCURRED
	int Variation_13();
	// @cmember Vectors - All non-existent columns - DB_E_ERRORSOCCURRED
	int Variation_14();
	// @cmember Vectors - No Vector Columns - S_OK
	int Variation_15();
	// @cmember Vectors - No Vectors and Non-Existent Columns - DB_E_ERRORSOCCURRED
	int Variation_16();
	// @cmember Vectors - Only Vector Columns - S_OK
	int Variation_17();
	// @cmember Vectors - Only Non-Existent Vector Columns - DB_E_ERRORSOCCURRED
	int Variation_18();
	// @cmember Vectors - Valid Vectors and Non-Existent Columns - DB_S_ERRORSOCCURRED
	int Variation_19();
	// @cmember Vectors - Valid Non-Vectors and Non-Existent Vector Columns - DB_S_ERRORSOCCURRED
	int Variation_20();
	// @cmember Empty
	int Variation_21();
	// @cmember Boundary - 0 columns -[0, NULL] and [0, valid]  no-op
	int Variation_22();
	// @cmember Boundary - [Valid, NULL] - E_INVALIDARG
	int Variation_23();
	// @cmember Empty
	int Variation_24();
	// @cmember Boundary - columnid - all valid dbkinds
	int Variation_25();
	// @cmember Boundary - columnid - invalid dbkinds
	int Variation_26();
	// @cmember Boundary - columnid - invalid [but close to original] dbkinds
	int Variation_27();
	// @cmember Boundary - cbMaxLen - ignored for fixed length types
	int Variation_28();
	// @cmember Boundary - cbMaxLen - DBSTATUS_S_TRUNCATION
	int Variation_29();
	// @cmember Boundary - cbMaxLen - invalid
	int Variation_30();
	// @cmember Empty
	int Variation_31();
	// @cmember Boundary - wType - all valid types and modifieres
	int Variation_32();
	// @cmember Boundary - wType - invalid types and invalid type modifiers
	int Variation_33();
	// @cmember Empty
	int Variation_34();
	// @cmember Boundary - bPrecision - make sure ignored on input for all types, except NUMERIC.
	int Variation_35();
	// @cmember Boundary - bScale - make sure ignored on input for all types, except NUMERIC.
	int Variation_36();
	// @cmember Boundary - Output Only - make sure cbDataLen, dwStatus, dwReserverd are ignored on input
	int Variation_37();
	// @cmember Boundary - Input - Make sure all pointers and input args are not changed on output, pData pointer, columnid [including all union pointers], cbMaxLen, dwReserved, wType.
	int Variation_38();
	// @cmember Empty
	int Variation_39();
	// @cmember Supply unaligned buffer for non-NULL bytes value
	int Variation_40();
	// @cmember Empty
	int Variation_41();
	// @cmember Empty
	int Variation_42();
	// @cmember Buffered Mode - All Columns - no BLOBs
	int Variation_43();
	// @cmember Buffered Mode - All Columns - BLOBs
	int Variation_44();
	// @cmember Buffered Mode - All Columns - Just extra columns
	int Variation_45();
	// @cmember Empty
	int Variation_46();
	// @cmember Aggregation - Command - > Row
	int Variation_47();
	// @cmember Aggregation - Session - > Row
	int Variation_48();
	// @cmember Aggregation - Rowset -> Row
	int Variation_49();
	// @cmember Empty
	int Variation_50();
	// @cmember Empty
	int Variation_51();
	// @cmember Properties - DBPROP_IRow
	int Variation_52();
	// @cmember Properties - DBPROP_OLEOBJECTS - DBPROPVAL_OO_ROWOBJECT
	int Variation_53();
	// @cmember Properties - DBPROP_OLEOBJECTS - DBPROPVAL_OO_SINGLETON
	int Variation_54();
	// @cmember Empty
	int Variation_55();
	// @cmember Properties - All Row Object Properties
	int Variation_56();
	// @cmember Properties - All Row Object Properties Optional
	int Variation_57();
	// @cmember Empty
	int Variation_58();
	// @cmember Properties - Rowset Properties
	int Variation_59();
	// @cmember Empty
	int Variation_60();
	// @cmember Threads - GetColumns seperate threads
	int Variation_61();
	// @cmember Empty
	int Variation_62();
	// @cmember Boundary - DB_E_DELETEDROW
	int Variation_63();
	// @cmember Boundary - DB_E_DELETEDROW - Bufferred Mode
	int Variation_64();
	// }} TCW_TESTVARS_END
} ;
// {{ TCW_TESTCASE(TCIRow_GetColumns)
#define THE_CLASS TCIRow_GetColumns
BEG_TEST_CASE(TCIRow_GetColumns, TCIRow, L"IRow::GetColumns")
	TEST_VARIATION(1, 		L"GetColumns - All columns - no BLOBs")
	TEST_VARIATION(2, 		L"GetColumns - All Columns - BLOBs")
	TEST_VARIATION(3, 		L"GetColumns - same column bound numerous times")
	TEST_VARIATION(4, 		L"GetColumns - BLOB Columns only")
	TEST_VARIATION(5, 		L"GetColumns - Each Column Seperatly")
	TEST_VARIATION(6, 		L"GetColumns - Asking for just Rowset columns")
	TEST_VARIATION(7, 		L"GetColumns - Asking for just Extra Row Columns")
	TEST_VARIATION(8, 		L"GetColumns - IUnknown Columns - native")
	TEST_VARIATION(9, 		L"Empty")
	TEST_VARIATION(10, 		L"GetColumns - Not Binding Value, pData is NULL")
	TEST_VARIATION(11, 		L"GetColumns - Value not bound for some columns")
	TEST_VARIATION(12, 		L"Empty")
	TEST_VARIATION(13, 		L"Vectors - Some valid, some non-existent columns - DB_S_ERRORSOCCURRED")
	TEST_VARIATION(14, 		L"Vectors - All non-existent columns - DB_E_ERRORSOCCURRED")
	TEST_VARIATION(15, 		L"Vectors - No Vector Columns - S_OK")
	TEST_VARIATION(16, 		L"Vectors - No Vectors and Non-Existent Columns - DB_E_ERRORSOCCURRED")
	TEST_VARIATION(17, 		L"Vectors - Only Vector Columns - S_OK")
	TEST_VARIATION(18, 		L"Vectors - Only Non-Existent Vector Columns - DB_E_ERRORSOCCURRED")
	TEST_VARIATION(19, 		L"Vectors - Valid Vectors and Non-Existent Columns - DB_S_ERRORSOCCURRED")
	TEST_VARIATION(20, 		L"Vectors - Valid Non-Vectors and Non-Existent Vector Columns - DB_S_ERRORSOCCURRED")
	TEST_VARIATION(21, 		L"Empty")
	TEST_VARIATION(22, 		L"Boundary - 0 columns -[0, NULL] and [0, valid]  no-op")
	TEST_VARIATION(23, 		L"Boundary - [Valid, NULL] - E_INVALIDARG")
	TEST_VARIATION(24, 		L"Empty")
	TEST_VARIATION(25, 		L"Boundary - columnid - all valid dbkinds")
	TEST_VARIATION(26, 		L"Boundary - columnid - invalid dbkinds")
	TEST_VARIATION(27, 		L"Boundary - columnid - invalid [but close to original] dbkinds")
	TEST_VARIATION(28, 		L"Boundary - cbMaxLen - ignored for fixed length types")
	TEST_VARIATION(29, 		L"Boundary - cbMaxLen - DBSTATUS_S_TRUNCATION")
	TEST_VARIATION(30, 		L"Boundary - cbMaxLen - invalid")
	TEST_VARIATION(31, 		L"Empty")
	TEST_VARIATION(32, 		L"Boundary - wType - all valid types and modifieres")
	TEST_VARIATION(33, 		L"Boundary - wType - invalid types and invalid type modifiers")
	TEST_VARIATION(34, 		L"Empty")
	TEST_VARIATION(35, 		L"Boundary - bPrecision - make sure ignored on input for all types, except NUMERIC.")
	TEST_VARIATION(36, 		L"Boundary - bScale - make sure ignored on input for all types, except NUMERIC.")
	TEST_VARIATION(37, 		L"Boundary - Output Only - make sure cbDataLen, dwStatus, dwReserverd are ignored on input")
	TEST_VARIATION(38, 		L"Boundary - Input - Make sure all pointers and input args are not changed on output, pData pointer, columnid [including all union pointers], cbMaxLen, dwReserved, wType.")
	TEST_VARIATION(39, 		L"Empty")
	TEST_VARIATION(40, 		L"Supply unaligned buffer for non-NULL bytes value")
	TEST_VARIATION(41, 		L"Empty")
	TEST_VARIATION(42, 		L"Empty")
	TEST_VARIATION(43, 		L"Buffered Mode - All Columns - no BLOBs")
	TEST_VARIATION(44, 		L"Buffered Mode - All Columns - BLOBs")
	TEST_VARIATION(45, 		L"Buffered Mode - All Columns - Just extra columns")
	TEST_VARIATION(46, 		L"Empty")
	TEST_VARIATION(47, 		L"Aggregation - Command - > Row")
	TEST_VARIATION(48, 		L"Aggregation - Session - > Row")
	TEST_VARIATION(49, 		L"Aggregation - Rowset -> Row")
	TEST_VARIATION(50, 		L"Empty")
	TEST_VARIATION(51, 		L"Empty")
	TEST_VARIATION(52, 		L"Properties - DBPROP_IRow")
	TEST_VARIATION(53, 		L"Properties - DBPROP_OLEOBJECTS - DBPROPVAL_OO_ROWOBJECT")
	TEST_VARIATION(54, 		L"Properties - DBPROP_OLEOBJECTS - DBPROPVAL_OO_SINGLETON")
	TEST_VARIATION(55, 		L"Empty")
	TEST_VARIATION(56, 		L"Properties - All Row Object Properties")
	TEST_VARIATION(57, 		L"Properties - All Row Object Properties Optional")
	TEST_VARIATION(58, 		L"Empty")
	TEST_VARIATION(59, 		L"Properties - Rowset Properties")
	TEST_VARIATION(60, 		L"Empty")
	TEST_VARIATION(61, 		L"Threads - GetColumns seperate threads")
	TEST_VARIATION(62, 		L"Empty")
	TEST_VARIATION(63, 		L"Boundary - DB_E_DELETEDROW")
	TEST_VARIATION(64, 		L"Boundary - DB_E_DELETEDROW - Bufferred Mode")
END_TEST_CASE()
#undef THE_CLASS
// }} TCW_TESTCASE_END
// }} TCW_TEST_CASE_MAP_END

// {{ TCW_TEST_CASE_MAP(TCIRow_GetSourceRowset)
//*-----------------------------------------------------------------------
// @class IRow::GetSourceRowset
//
class TCIRow_GetSourceRowset : public TCIRow {
private:
	// @cmember Static array of variations
	DECLARE_TEST_CASE_DATA();

public:
	// {{ TCW_DECLARE_FUNCS
	// @cmember Execution Routine
	DECLARE_TEST_CASE_FUNCS(TCIRow_GetSourceRowset,TCIRow);
	// }} TCW_DECLARE_FUNCS_END

	// @cmember Initialization Routine
	virtual BOOL Init();
	// @cmember Termination Routine
	virtual BOOL Terminate();

	// {{ TCW_TESTVARS()
	// @cmember riid - All Mandatory interfaces
	int Variation_1();
	// @cmember Empty
	int Variation_2();
	// @cmember Optional Args - [any riid, NULL, NULL] - S_OK
	int Variation_3();
	// @cmember Optional Args - [any riid, NULL, valid] - S_OK with hRow
	int Variation_4();
	// @cmember Optional Args - [IID_IUnknown, valid, NULL] - S_OK with Rowset
	int Variation_5();
	// @cmember Optional Args - [IID_IRowset, valid, valid] - S_OK with Rowset and hRow
	int Variation_6();
	// @cmember Empty
	int Variation_7();
	// @cmember Sequence - Execute -> Row -> GetSourceRowset
	int Variation_8();
	// @cmember Sequence - Execute -> Rowset -> Row -> GetSourceRowset
	int Variation_9();
	// @cmember Sequence - OpenRowset -> Row -> Release Rowset -> GetSourceRowset
	int Variation_10();
	// @cmember Sequence - OpenRowset -> Rowset -> Row -> Release Rowset -> GetSourceRowset
	int Variation_11();
	// @cmember Empty
	int Variation_12();
	// @cmember Multiple - GetSourceRowset from numerous child row objects
	int Variation_13();
	// @cmember Multiple - Numerous Rowsets open, verify correct parent
	int Variation_14();
	// @cmember Empty
	int Variation_15();
	// @cmember Aggregation - Rowset -> Agg Row -> GetSourceRowset
	int Variation_16();
	// @cmember Aggregation - Agg Rowset -> Row -> GetSourceRowset
	int Variation_17();
	// @cmember Empty
	int Variation_18();
	// @cmember Threads - GetSourceRowset
	int Variation_19();
	// }} TCW_TESTVARS_END
} ;
// {{ TCW_TESTCASE(TCIRow_GetSourceRowset)
#define THE_CLASS TCIRow_GetSourceRowset
BEG_TEST_CASE(TCIRow_GetSourceRowset, TCIRow, L"IRow::GetSourceRowset")
	TEST_VARIATION(1, 		L"riid - All Mandatory interfaces")
	TEST_VARIATION(2, 		L"Empty")
	TEST_VARIATION(3, 		L"Optional Args - [any riid, NULL, NULL] - S_OK")
	TEST_VARIATION(4, 		L"Optional Args - [any riid, NULL, valid] - S_OK with hRow")
	TEST_VARIATION(5, 		L"Optional Args - [IID_IUnknown, valid, NULL] - S_OK with Rowset")
	TEST_VARIATION(6, 		L"Optional Args - [IID_IRowset, valid, valid] - S_OK with Rowset and hRow")
	TEST_VARIATION(7, 		L"Empty")
	TEST_VARIATION(8, 		L"Sequence - Execute -> Row -> GetSourceRowset")
	TEST_VARIATION(9, 		L"Sequence - Execute -> Rowset -> Row -> GetSourceRowset")
	TEST_VARIATION(10, 		L"Sequence - OpenRowset -> Row -> Release Rowset -> GetSourceRowset")
	TEST_VARIATION(11, 		L"Sequence - OpenRowset -> Rowset -> Row -> Release Rowset -> GetSourceRowset")
	TEST_VARIATION(12, 		L"Empty")
	TEST_VARIATION(13, 		L"Multiple - GetSourceRowset from numerous child row objects")
	TEST_VARIATION(14, 		L"Multiple - Numerous Rowsets open, verify correct parent")
	TEST_VARIATION(15, 		L"Empty")
	TEST_VARIATION(16, 		L"Aggregation - Rowset -> Agg Row -> GetSourceRowset")
	TEST_VARIATION(17, 		L"Aggregation - Agg Rowset -> Row -> GetSourceRowset")
	TEST_VARIATION(18, 		L"Empty")
	TEST_VARIATION(19, 		L"Threads - GetSourceRowset")
END_TEST_CASE()
#undef THE_CLASS
// }} TCW_TESTCASE_END
// }} TCW_TEST_CASE_MAP_END

// {{ TCW_TEST_CASE_MAP(TCIRow_Open)
//*-----------------------------------------------------------------------
// @class IRow::Open
//
class TCIRow_Open : public TCIRow {
private:
	// @cmember Static array of variations
	DECLARE_TEST_CASE_DATA();

public:
	// {{ TCW_DECLARE_FUNCS
	// @cmember Execution Routine
	DECLARE_TEST_CASE_FUNCS(TCIRow_Open,TCIRow);
	// }} TCW_DECLARE_FUNCS_END

	// @cmember Initialization Routine
	virtual BOOL Init();
	// @cmember Termination Routine
	virtual BOOL Terminate();

	// {{ TCW_TESTVARS()
	// @cmember GUID_NULL - All columns as Default Object
	int Variation_1();
	// @cmember DBGUID_STREAM - All Mandatory and Optional TStream interfaces
	int Variation_2();
	// @cmember DBGUID_STREAM - Compare data with expected
	int Variation_3();
	// @cmember DBGUID_STREAM - Twice on the same column
	int Variation_4();
	// @cmember DBGUID_STREAM - Multiple Objects open on different columns
	int Variation_5();
	// @cmember DBGUID_STREAM - Bufferred Mode
	int Variation_6();
	// @cmember Empty
	int Variation_7();
	// @cmember DBGUID_ROW - All Mandatory and Optional TRow interfaces
	int Variation_8();
	// @cmember DBGUID_ROW - Get all row columns and verify
	int Variation_9();
	// @cmember DBGUID_ROW - GetSourceRowset
	int Variation_10();
	// @cmember DBGUID_ROW - Twice on the same column
	int Variation_11();
	// @cmember DBGUID_ROW - Multiple Objects open on different columns
	int Variation_12();
	// @cmember DBGUID_ROW - Bufferred Mode
	int Variation_13();
	// @cmember Empty
	int Variation_14();
	// @cmember DBGUID_ROWSET - All Mandatory and Optional TRowset interfaces
	int Variation_15();
	// @cmember DBGUID_ROWSET - Twice on the same column
	int Variation_16();
	// @cmember DBGUID_ROWSET - Buffered mode
	int Variation_17();
	// @cmember Empty
	int Variation_18();
	// @cmember DEFAULTSTREAM
	int Variation_19();
	// @cmember DEFAULTSTREAM - Buffered mode
	int Variation_20();
	// @cmember Empty
	int Variation_21();
	// @cmember Boundary - E_INVALIDARG
	int Variation_22();
	// @cmember Boundary - DB_E_BADCOLUMNID - invalid DBID
	int Variation_23();
	// @cmember Boundary - DB_E_BADCOLUMNID - invalid [but close to original] DBID
	int Variation_24();
	// @cmember Boundary - DB_E_BADCOLUMNID - shortcut DBID that doesn't exist
	int Variation_25();
	// @cmember Boundary - DB_E_OBJECTMISMATCH
	int Variation_26();
	// @cmember Boundary - DB_E_OBJECTOPEN
	int Variation_27();
	// @cmember Boundary - DB_E_NOTFOUND
	int Variation_28();
	// @cmember Boundary - DB_E_DELETEDROW
	int Variation_29();
	// @cmember Empty
	int Variation_30();
	// @cmember Stream Object - Read the data in chunks
	int Variation_31();
	// @cmember Empty
	int Variation_32();
	// @cmember Aggregation - Row -> Open -> GetSourceRow
	int Variation_33();
	// @cmember Empty
	int Variation_34();
	// @cmember Threads - Open over the same column
	int Variation_35();
	// @cmember Threads - Open over different columns
	int Variation_36();
	// }} TCW_TESTVARS_END
} ;
// {{ TCW_TESTCASE(TCIRow_Open)
#define THE_CLASS TCIRow_Open
BEG_TEST_CASE(TCIRow_Open, TCIRow, L"IRow::Open")
	TEST_VARIATION(1, 		L"GUID_NULL - All columns as Default Object")
	TEST_VARIATION(2, 		L"DBGUID_STREAM - All Mandatory and Optional TStream interfaces")
	TEST_VARIATION(3, 		L"DBGUID_STREAM - Compare data with expected")
	TEST_VARIATION(4, 		L"DBGUID_STREAM - Twice on the same column")
	TEST_VARIATION(5, 		L"DBGUID_STREAM - Multiple Objects open on different columns")
	TEST_VARIATION(6, 		L"DBGUID_STREAM - Bufferred Mode")
	TEST_VARIATION(7, 		L"Empty")
	TEST_VARIATION(8, 		L"DBGUID_ROW - All Mandatory and Optional TRow interfaces")
	TEST_VARIATION(9, 		L"DBGUID_ROW - Get all row columns and verify")
	TEST_VARIATION(10, 		L"DBGUID_ROW - GetSourceRowset")
	TEST_VARIATION(11, 		L"DBGUID_ROW - Twice on the same column")
	TEST_VARIATION(12, 		L"DBGUID_ROW - Multiple Objects open on different columns")
	TEST_VARIATION(13, 		L"DBGUID_ROW - Bufferred Mode")
	TEST_VARIATION(14, 		L"Empty")
	TEST_VARIATION(15, 		L"DBGUID_ROWSET - All Mandatory and Optional TRowset interfaces")
	TEST_VARIATION(16, 		L"DBGUID_ROWSET - Twice on the same column")
	TEST_VARIATION(17, 		L"DBGUID_ROWSET - Buffered mode")
	TEST_VARIATION(18, 		L"Empty")
	TEST_VARIATION(19, 		L"DEFAULTSTREAM")
	TEST_VARIATION(20, 		L"DEFAULTSTREAM - Buffered mode")
	TEST_VARIATION(21, 		L"Empty")
	TEST_VARIATION(22, 		L"Boundary - E_INVALIDARG")
	TEST_VARIATION(23, 		L"Boundary - DB_E_BADCOLUMNID - invalid DBID")
	TEST_VARIATION(24, 		L"Boundary - DB_E_BADCOLUMNID - invalid [but close to original] DBID")
	TEST_VARIATION(25, 		L"Boundary - DB_E_BADCOLUMNID - shortcut DBID that doesn't exist")
	TEST_VARIATION(26, 		L"Boundary - DB_E_OBJECTMISMATCH")
	TEST_VARIATION(27, 		L"Boundary - DB_E_OBJECTOPEN")
	TEST_VARIATION(28, 		L"Boundary - DB_E_NOTFOUND")
	TEST_VARIATION(29, 		L"Boundary - DB_E_DELETEDROW")
	TEST_VARIATION(30, 		L"Empty")
	TEST_VARIATION(31, 		L"Stream Object - Read the data in chunks")
	TEST_VARIATION(32, 		L"Empty")
	TEST_VARIATION(33, 		L"Aggregation - Row -> Open -> GetSourceRow")
	TEST_VARIATION(34, 		L"Empty")
	TEST_VARIATION(35, 		L"Threads - Open over the same column")
	TEST_VARIATION(36, 		L"Threads - Open over different columns")
END_TEST_CASE()
#undef THE_CLASS
// }} TCW_TESTCASE_END
// }} TCW_TEST_CASE_MAP_END

// {{ TCW_TEST_CASE_MAP(TCTransactions)
//*-----------------------------------------------------------------------
// @class IRow inside Transactions
//
class TCTransactions : public CTransaction {
private:
	// @cmember Static array of variations
	DECLARE_TEST_CASE_DATA();

public:
	// {{ TCW_DECLARE_FUNCS
	// @cmember Execution Routine
	DECLARE_TEST_CASE_FUNCS(TCTransactions,CTransaction);
	// }} TCW_DECLARE_FUNCS_END

	// @cmember Initialization Routine
	virtual BOOL Init();
	// @cmember Termination Routine
	virtual BOOL Terminate();

	//Helpers
	virtual BOOL VerifyTransaction(BOOL fCommit, BOOL fRetaining);

	// {{ TCW_TESTVARS()
	// @cmember ABORT with fRetaining TRUE
	int Variation_1();
	// @cmember ABORT with fRetaining FALSE
	int Variation_2();
	// @cmember COMMIT with fRetaining TRUE
	int Variation_3();
	// @cmember COMMIT with fRetaining FALSE
	int Variation_4();
	// }} TCW_TESTVARS_END
} ;
// {{ TCW_TESTCASE(TCTransactions)
#define THE_CLASS TCTransactions
BEG_TEST_CASE(TCTransactions, CTransaction, L"IRow inside Transactions")
	TEST_VARIATION(1, 		L"ABORT with fRetaining TRUE")
	TEST_VARIATION(2, 		L"ABORT with fRetaining FALSE")
	TEST_VARIATION(3, 		L"COMMIT with fRetaining TRUE")
	TEST_VARIATION(4, 		L"COMMIT with fRetaining FALSE")
END_TEST_CASE()
#undef THE_CLASS
// }} TCW_TESTCASE_END
// }} TCW_TEST_CASE_MAP_END

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Test Case Section
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

// }} END_DECLARE_TEST_CASES()

// {{ TCW_TESTMODULE(ThisModule)
TEST_MODULE(5, ThisModule, gwszModuleDescrip)
	TEST_CASE(1, TCIRow_IUnknown)
	TEST_CASE(2, TCIRow_GetColumns)
	TEST_CASE(3, TCIRow_GetSourceRowset)
	TEST_CASE(4, TCIRow_Open)
	TEST_CASE(5, TCTransactions)
END_TEST_MODULE()
// }} TCW_TESTMODULE_END

////////////////////////////////////////////////////////////////////////////
//  TCTransactionsVerifyTransaction
//
////////////////////////////////////////////////////////////////////////////
BOOL TCTransactions::VerifyTransaction(BOOL fCommit, BOOL fRetaining)
{
	HROW				hRow;
	IGetRow*			pIGetRow = NULL;
	BOOL				fPreserving = FALSE;
	CRowset				RowsetA;
	CRowObject			RowObjectA;
	ISequentialStream*	pISeqStream = NULL;
	IRowsetInfo*		pIRowsetInfo = INVALID(IRowsetInfo*);
	HROW				hSourceRow = NULL;

	//start a transaction
	TESTC(StartTransaction(SELECT_ALLFROMTBL, (IUnknown**)&pIGetRow, 0, NULL));
	TESTC_(RowsetA.CreateRowset(pIGetRow),S_OK);

	//Obtain a row object - before we commit/abort the transaction
	TESTC_(RowsetA.GetNextRows(&hRow),S_OK);
	TESTC_(RowObjectA.CreateRowObject(RowsetA.pIRowset(), hRow),S_OK);

	//commit the transaction with fRetaining==TRUE
	if(fCommit)
	{
		TESTC(GetCommit(fRetaining))
		fPreserving = m_fCommitPreserve;
	}
	else
	{
		TESTC(GetAbort(fRetaining))
		fPreserving = m_fAbortPreserve;
	}

	if(fPreserving)
	{
		//fully functional

		//IRow::GetColumns
		TESTC(RowObjectA.VerifyGetColumns(FIRST_ROW, RowsetA.pTable()));

		//IRow::GetSourceRowset
		TESTC_(RowObjectA.GetSourceRowset(IID_IRowsetInfo, (IUnknown**)&pIRowsetInfo, NULL), S_OK);
		TESTC(DefaultObjectTesting(pIRowsetInfo, ROWSET_INTERFACE));

		//IRow::Open (open the default stream - note it may not exist for every row)
		//NOTE: Our helper takes care of all validation of the returned object...
		TEST2C_(RowObjectA.Open(NULL, &DBROWCOL_DEFAULTSTREAM, DBGUID_STREAM,
			IID_ISequentialStream, (IUnknown**)&pISeqStream),S_OK, DB_E_BADCOLUMNID);
	}
	else
	{
		//zombie

		//IRow::GetColumns
		TESTC_(RowObjectA.GetColumns(RowObjectA.m_cColAccess, RowObjectA.m_rgColAccess),E_UNEXPECTED);

		//Make sure it NULLs the output params on error...
		hSourceRow = INVALID(HROW);
		pIRowsetInfo = INVALID(IRowsetInfo*);

		//IRow::GetSourceRowset
		TESTC_(RowObjectA.GetSourceRowset(IID_IRowsetInfo, (IUnknown**)&pIRowsetInfo, &hSourceRow), E_UNEXPECTED);
		TESTC(hSourceRow == NULL);
		TESTC(pIRowsetInfo == NULL);

		//IRow::GetSourceRowset
		//This time not asking for an HROW, as its more difficult for the provider to determine
		//zombie, if just getting a parent object, vs. row handle (ie: ConfProv)
		TESTC_(RowObjectA.GetSourceRowset(IID_IRowsetInfo, (IUnknown**)&pIRowsetInfo, NULL), E_UNEXPECTED);
		TESTC(pIRowsetInfo == NULL);

		//IRow::Open (open the default stream - note it may not exist for every row)
		//NOTE: Our helper takes care of all validation of the returned object...
		TESTC_(RowObjectA.Open(NULL, &DBROWCOL_DEFAULTSTREAM, DBGUID_STREAM,
			IID_ISequentialStream, (IUnknown**)&pISeqStream), E_UNEXPECTED);
		TESTC(pISeqStream == NULL);

	}

CLEANUP:
	SAFE_RELEASE(pIGetRow);
	SAFE_RELEASE(pISeqStream);
	if(pIRowsetInfo != INVALID(IRowsetInfo*))
		SAFE_RELEASE(pIRowsetInfo);

	//clean up.
	CleanUpTransaction(fRetaining ? S_OK : XACT_E_NOTRANSACTION);
	TRETURN
}

// {{ TCW_TC_PROTOTYPE(TCIRow_IUnknown)
//*-----------------------------------------------------------------------
//| Test Case:		TCIRow_IUnknown - IRow IUnknown scenarios
//| Created:  	8/5/98
//*-----------------------------------------------------------------------

//*-----------------------------------------------------------------------
// @mfunc TestCase Initialization Routine
//
// @rdesc TRUE or FALSE
//
BOOL TCIRow_IUnknown::Init()
{
	// {{ TCW_INIT_BASECLASS_CHECK
	if(TCIRow::Init())
	// }}
	{
		return TRUE;
	}
	return FALSE;
}

// {{ TCW_VAR_PROTOTYPE(1)
//*-----------------------------------------------------------------------
// @mfunc IUnknown - QI Mandatory Interfaces
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCIRow_IUnknown::Variation_1()
{
	//Do some default IUnknown interface testing
	return DefaultObjectTesting(m_pCRowObject->pIRow(), ROW_INTERFACE);
}
// }} TCW_VAR_PROTOTYPE_END

// {{ TCW_VAR_PROTOTYPE(2)
//*-----------------------------------------------------------------------
// @mfunc IUnknown - QI Optional Interfaces
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCIRow_IUnknown::Variation_2()
{
	//Do some default IUnknown interface testing
	return DefaultObjectTesting(m_pCRowObject->pIRow(), ROW_INTERFACE);
}
// }} TCW_VAR_PROTOTYPE_END

// {{ TCW_VAR_PROTOTYPE(3)
//*-----------------------------------------------------------------------
// @mfunc IUnknown - AddRef / Release
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCIRow_IUnknown::Variation_3()
{
	//Do some default IUnknown interface testing
	return DefaultObjectTesting(m_pCRowObject->pIRow(), ROW_INTERFACE);
}
// }} TCW_VAR_PROTOTYPE_END

// {{ TCW_TERMINATE_METHOD
//*-----------------------------------------------------------------------
// @mfunc TestCase Termination Routine
//
// @rdesc TEST_PASS or TEST_FAIL
//
BOOL TCIRow_IUnknown::Terminate()
{
// {{ TCW_TERM_BASECLASS_CHECK2
	return(TCIRow::Terminate());
} 	// }}
// }} TCW_TERMINATE_METHOD_END
// }} TCW_TC_PROTOTYPE_END

// {{ TCW_TC_PROTOTYPE(TCIRow_GetColumns)
//*-----------------------------------------------------------------------
//| Test Case:		TCIRow_GetColumns - IRow::GetColumns
//| Created:  	8/5/98
//*-----------------------------------------------------------------------

//*-----------------------------------------------------------------------
// @mfunc TestCase Initialization Routine
//
// @rdesc TRUE or FALSE
//
BOOL TCIRow_GetColumns::Init()
{
	// {{ TCW_INIT_BASECLASS_CHECK
	if(TCIRow::Init())
	// }}
	{
		return TRUE;
	}
	return FALSE;
}

// {{ TCW_VAR_PROTOTYPE(1)
//*-----------------------------------------------------------------------
// @mfunc GetColumns - All columns - no BLOBs
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCIRow_GetColumns::Variation_1()
{
	TBEGIN

	//Loop through all the rows in the rowset, verify the columns...
	TESTC(VerifyGetColumnsAllRows(NULL, ALL_COLS_BOUND));

CLEANUP:
	TRETURN
}
// }} TCW_VAR_PROTOTYPE_END

// {{ TCW_VAR_PROTOTYPE(2)
//*-----------------------------------------------------------------------
// @mfunc GetColumns - All Columns - BLOBs
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCIRow_GetColumns::Variation_2()
{
	TBEGIN

	//Loop through all the rows in the rowset, verify the columns...
	TESTC(VerifyGetColumnsAllRows(NULL, ALL_COLS_BOUND, BLOB_LONG));

CLEANUP:
	TRETURN
}
// }} TCW_VAR_PROTOTYPE_END

// {{ TCW_VAR_PROTOTYPE(3)
//*-----------------------------------------------------------------------
// @mfunc GetColumns - same column bound numerous times
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCIRow_GetColumns::Variation_3()
{
	TBEGIN
	IColumnsInfo* pIColumnsInfo = NULL;
	DBORDINAL i,cColumns=0;
	DBCOLUMNINFO* rgColumnInfo = NULL;
	WCHAR* pStringBuffer = NULL;
	DBORDINAL  cColOrds = 0;
	DBORDINAL* rgColOrds = NULL;

	//Use a new rowset, and ask for a non-forward-only cursor,
	//so we can obtain the data multiple times.
	CRowset RowsetA;
	RowsetA.SetSettableProperty(DBPROP_ACCESSORDER, DBPROPSET_ROWSET, (void*)DBPROPVAL_AO_RANDOM, DBTYPE_I4);
	TESTC_PROVIDER(RowsetA.CreateRowset()==S_OK);

	//Get the ColumnInfo
	TESTC(VerifyInterface(m_pCRowObject->pIRow(), IID_IColumnsInfo, ROW_INTERFACE, (IUnknown**)&pIColumnsInfo));
	TESTC_(pIColumnsInfo->GetColumnInfo(&cColumns, &rgColumnInfo, &pStringBuffer),S_OK);
	SAFE_ALLOC(rgColOrds, DBORDINAL, cColumns);

	//Loop through each column seperatly...
	for(i=0; i<cColumns; i++)
	{
		//Fill in the Col Ordinals with numerous duplicates
		cColOrds = 0;
		for(DBORDINAL iDup=0; iDup<i; iDup++)
		{
			rgColOrds[iDup] = rgColumnInfo[i].iOrdinal;
			cColOrds++;
		}

		//Loop through all the rows in the rowset, verify the columns...
		TESTC(VerifyGetColumnsAllRows(&RowsetA, USE_COLS_TO_BIND_ARRAY, BLOB_LONG, FORWARD,
					NO_COLS_BY_REF,	DBTYPE_EMPTY, cColOrds, rgColOrds));
	}

CLEANUP:
	SAFE_FREE(rgColumnInfo);
	SAFE_FREE(pStringBuffer);
	SAFE_RELEASE(pIColumnsInfo);
	SAFE_FREE(rgColOrds);
	TRETURN
}
// }} TCW_VAR_PROTOTYPE_END

// {{ TCW_VAR_PROTOTYPE(4)
//*-----------------------------------------------------------------------
// @mfunc GetColumns - BLOB Columns only
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCIRow_GetColumns::Variation_4()
{
	TBEGIN

	//Loop through all the rows in the rowset, verify the columns...
	TESTC(VerifyGetColumnsAllRows(NULL, BLOB_COLS_BOUND, BLOB_LONG));

CLEANUP:
	TRETURN
}
// }} TCW_VAR_PROTOTYPE_END

// {{ TCW_VAR_PROTOTYPE(5)
//*-----------------------------------------------------------------------
// @mfunc GetColumns - Each Column Seperatly
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCIRow_GetColumns::Variation_5()
{
	TBEGIN
	IColumnsInfo* pIColumnsInfo = NULL;
	DBORDINAL i,cColumns=0;
	DBCOLUMNINFO* rgColumnInfo = NULL;
	WCHAR* pStringBuffer = NULL;

	//Get the ColumnInfo
	TESTC(VerifyInterface(m_pCRowObject->pIRow(), IID_IColumnsInfo, ROW_INTERFACE, (IUnknown**)&pIColumnsInfo));
	TESTC_(pIColumnsInfo->GetColumnInfo(&cColumns, &rgColumnInfo, &pStringBuffer),S_OK);

	//Loop through each column seperatly...
	for(i=0; i<cColumns; i++)
	{
		DBCOLUMNINFO* pColInfo = &rgColumnInfo[i];

		//Loop through all the rows in the rowset, verify the columns...
		TESTC(VerifyGetColumnsAllRows(NULL, USE_COLS_TO_BIND_ARRAY, BLOB_LONG, FORWARD,
					NO_COLS_BY_REF,	DBTYPE_EMPTY, 1, &pColInfo->iOrdinal));

		//While were doing each column seperately also only bind status and length
		TESTC(VerifyGetColumnsAllRows(NULL, USE_COLS_TO_BIND_ARRAY, BLOB_LONG, FORWARD,
					NO_COLS_BY_REF,	DBTYPE_EMPTY, 1, &pColInfo->iOrdinal, DBPART_LENGTH|DBPART_STATUS));

		//Also for BLOBS bind (seperatly) as streams
		if(pColInfo->dwFlags & DBCOLUMNFLAGS_ISLONG)
		{
			TESTC(VerifyGetColumnsAllRows(NULL, USE_COLS_TO_BIND_ARRAY, BLOB_IID_IUNKNOWN, FORWARD,
					NO_COLS_BY_REF,	DBTYPE_EMPTY, 1, &pColInfo->iOrdinal));

			//While were doing each column seperately also only bind status and length
			TESTC(VerifyGetColumnsAllRows(NULL, USE_COLS_TO_BIND_ARRAY, BLOB_IID_IUNKNOWN, FORWARD,
					NO_COLS_BY_REF,	DBTYPE_EMPTY, 1, &pColInfo->iOrdinal, DBPART_LENGTH|DBPART_STATUS));
		}

	}

CLEANUP:
	SAFE_FREE(rgColumnInfo);
	SAFE_FREE(pStringBuffer);
	SAFE_RELEASE(pIColumnsInfo);
	TRETURN
}
// }} TCW_VAR_PROTOTYPE_END

// {{ TCW_VAR_PROTOTYPE(6)
//*-----------------------------------------------------------------------
// @mfunc GetColumns - Asking for just Rowset columns
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCIRow_GetColumns::Variation_6()
{
	TBEGIN
	HRESULT hr = S_OK;
	DBORDINAL cColAccess = 0;
	DBCOLUMNACCESS* rgColAccess = NULL;

	//Obtain a row object
	CRowObject RowObjectA;
	TESTC_(GetRowObject(FIRST_ROW, &RowObjectA), S_OK);

	//Create ColAccess structures from the Rowset bindings
	TESTC_(hr = RowObjectA.BindingsToColAccess(m_cBindings, m_rgBinding, m_pData, &cColAccess, &rgColAccess),S_OK);

	//IRow::GetColumns
	TESTC_(hr = RowObjectA.GetColumns(cColAccess, rgColAccess),S_OK);

	//Compare Data for this row object
	TESTC(RowObjectA.CompareColAccess(cColAccess, rgColAccess, FIRST_ROW, pTable()));

CLEANUP:
	FreeColAccess(cColAccess, rgColAccess);
	TRETURN
}
// }} TCW_VAR_PROTOTYPE_END

// {{ TCW_VAR_PROTOTYPE(7)
//*-----------------------------------------------------------------------
// @mfunc GetColumns - Asking for just Extra Row Columns
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCIRow_GetColumns::Variation_7()
{
	TBEGIN
	HRESULT hr = S_OK;
	DBORDINAL cColAccess = 0;
	DBCOLUMNACCESS* rgColAccess = NULL;
	void* pData = NULL;

	DBORDINAL cColumns = 0;
	DBORDINAL* rgColOrdinals = NULL;

	//Obtain a row object
	CRowObject RowObjectA;
	TESTC_(GetRowObject(FIRST_ROW, &RowObjectA), S_OK);

	//Obtain the just the Extra columns
	TEST2C_(hr = RowObjectA.GetExtraColumnInfo(&cColumns, NULL, NULL, &rgColOrdinals),S_OK,DB_E_NOSOURCEOBJECT);
	if(hr == DB_E_NOSOURCEOBJECT)
	{
		odtLog<<L"This provider does not support IRow::GetSourceRowset\n";
		TESTB = TEST_SKIPPED;
		goto CLEANUP;
	}

	//Create the ColAccess Structures for just the extra columns...
	TESTC_(hr = RowObjectA.CreateColAccess(&cColAccess, &rgColAccess, &pData, NULL, USE_COLS_TO_BIND_ARRAY, BLOB_LONG, FORWARD, NO_COLS_BY_REF, DBTYPE_EMPTY, cColumns, rgColOrdinals),S_OK);

	//IRow::GetColumns
	TESTC_(hr = RowObjectA.GetColumns(cColAccess, rgColAccess),S_OK);

	//Compare Data for this row object
	TESTC(RowObjectA.CompareColAccess(cColAccess, rgColAccess, FIRST_ROW, pTable()));

CLEANUP:
	FreeColAccess(cColAccess, rgColAccess);
	SAFE_FREE(pData);
	SAFE_FREE(rgColOrdinals);
	TRETURN
}
// }} TCW_VAR_PROTOTYPE_END

// {{ TCW_VAR_PROTOTYPE(8)
//*-----------------------------------------------------------------------
// @mfunc GetColumns - IUnknown Columns - native
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCIRow_GetColumns::Variation_8()
{
	TBEGIN

	//Loop through all the rows in the rowset, verify the columns...
	TESTC(VerifyGetColumnsAllRows(NULL, BLOB_COLS_BOUND, BLOB_IID_IUNKNOWN));

CLEANUP:
	TRETURN
}
// }} TCW_VAR_PROTOTYPE_END

// {{ TCW_VAR_PROTOTYPE(9)
//*-----------------------------------------------------------------------
// @mfunc Empty
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCIRow_GetColumns::Variation_9()
{
	return TEST_SKIPPED;
}
// }} TCW_VAR_PROTOTYPE_END

// {{ TCW_VAR_PROTOTYPE(10)
//*-----------------------------------------------------------------------
// @mfunc GetColumns - Not Binding Value, pData is NULL
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCIRow_GetColumns::Variation_10()
{
	TBEGIN

	//Only Bind the LENGTH and STATUS (pData == NULL - indicates VALUE is not bound)
	//Loop through all the rows in the rowset, verify the columns...
	TESTC(VerifyGetColumnsAllRows(NULL, ALL_COLS_BOUND, BLOB_LONG, FORWARD, NO_COLS_BY_REF, DBTYPE_EMPTY, 0, NULL, DBPART_LENGTH|DBPART_STATUS));

	//Also make sure we bind the IUnknown columns as NULL as well...
	TESTC(VerifyGetColumnsAllRows(NULL, ALL_COLS_BOUND, BLOB_IID_IUNKNOWN, FORWARD, NO_COLS_BY_REF, DBTYPE_EMPTY, 0, NULL, DBPART_LENGTH|DBPART_STATUS));

CLEANUP:
	TRETURN
}
// }} TCW_VAR_PROTOTYPE_END

// {{ TCW_VAR_PROTOTYPE(11)
//*-----------------------------------------------------------------------
// @mfunc GetColumns - Value not bound for some columns
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCIRow_GetColumns::Variation_11()
{
	TBEGIN
	HRESULT hr = S_OK;
	DBORDINAL i,cColAccess = 0;
	DBCOLUMNACCESS* rgColAccess = NULL;

	//Obtain a row object
	CRowObject RowObjectA;
	TESTC_(GetRowObject(FIRST_ROW, &RowObjectA), S_OK);

	//Create ColAccess structures from the Rowset bindings
	TESTC_(hr = RowObjectA.BindingsToColAccess(m_cBindings, m_rgBinding, m_pData, &cColAccess, &rgColAccess),S_OK);

	//For some columns, don't bind the value
	for(i=0; i<cColAccess; i++)
	{
		//Don't bind value for every other column...
		//NOTE: We have one allocated pData that all the structures point into, so there
		//is nothing to free, we just set this pointer to NULL...
		if(i%2)
			rgColAccess[i].pData = NULL;
	}

	//IRow::GetColumns
	TESTC_(hr = RowObjectA.GetColumns(cColAccess, rgColAccess),S_OK);

	//Compare Data for this row object
	TESTC(RowObjectA.CompareColAccess(cColAccess, rgColAccess, FIRST_ROW, pTable()));

	//Make sure on output, that our pData's are unchanged!
	for(i=0; i<cColAccess; i++)
	{
		if(i%2)
		{
			TESTC(rgColAccess[i].pData == NULL);
		}
		else
		{
			TESTC(rgColAccess[i].pData != NULL);
		}
	}

CLEANUP:
	FreeColAccess(cColAccess, rgColAccess);
	TRETURN
}
// }} TCW_VAR_PROTOTYPE_END

// {{ TCW_VAR_PROTOTYPE(12)
//*-----------------------------------------------------------------------
// @mfunc Empty
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCIRow_GetColumns::Variation_12()
{
	return TEST_SKIPPED;
}
// }} TCW_VAR_PROTOTYPE_END

// {{ TCW_VAR_PROTOTYPE(13)
//*-----------------------------------------------------------------------
// @mfunc Vectors - Some valid, some non-existent columns - DB_S_ERRORSOCCURRED
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCIRow_GetColumns::Variation_13()
{
	TBEGIN
	DBORDINAL cColAccess = 0;
	DBCOLUMNACCESS* rgColAccess = NULL;
	DBORDINAL cColAccess2 = 0;
	DBCOLUMNACCESS* rgColAccess2 = NULL;
	void* pData = NULL;
	void* pData2 = NULL;
	DBORDINAL cColInvalid = 0;
	DBCOLUMNACCESS* rgColInvalid = NULL;

	//Obtain a row object
	CRowObject RowObjectA;
	TESTC_(GetRowObject(FIRST_ROW, &RowObjectA), S_OK);

	//Create the ColAccess Structures (for all columns)...
	//NOTE: We do this twice, since we want to test invalid columnid within valid ids.
	//A memcpy is not sufficient, since ColAccess contains ColIds which have to be allocated,
	//as well as memory location buffers, etc.  Easier to just call twice...
	TESTC_(RowObjectA.CreateColAccess(&cColAccess, &rgColAccess, &pData, NULL, ALL_COLS_BOUND, BLOB_LONG),S_OK);
	TESTC_(RowObjectA.CreateColAccess(&cColAccess2, &rgColAccess2, &pData2, NULL, ALL_COLS_BOUND, BLOB_LONG),S_OK);

	//Now create complete ColAccess array, containing:
	//Format = 1 Invalid, All Valid, 2 Invalid, All Valid, 1 Invalid
	cColInvalid = 1 + cColAccess + 2 + cColAccess2 + 1;
	SAFE_ALLOC(rgColInvalid, DBCOLUMNACCESS, cColInvalid);
	//Create "Invalid" ColIDs
	memset(rgColInvalid, 0, (size_t)(sizeof(DBCOLUMNACCESS) * cColInvalid));
	//Create First set of All Valid
	memcpy(&rgColInvalid[1], rgColAccess, (size_t)(sizeof(DBCOLUMNACCESS)*cColAccess));
	//Create Second set of All Valid
	memcpy(&rgColInvalid[1 + cColAccess + 2], rgColAccess2, (size_t)(sizeof(DBCOLUMNACCESS)*cColAccess2));

	//IRow::GetColumns
	TESTC_(RowObjectA.GetColumns(cColInvalid, rgColInvalid),DB_S_ERRORSOCCURRED);

	//Verify Status'
	TESTC(rgColInvalid[0].dwStatus == DBSTATUS_E_DOESNOTEXIST);
	TESTC(rgColInvalid[1 + cColAccess + 0].dwStatus == DBSTATUS_E_DOESNOTEXIST);
	TESTC(rgColInvalid[1 + cColAccess + 1].dwStatus == DBSTATUS_E_DOESNOTEXIST);
	TESTC(rgColInvalid[1 + cColAccess + 2 + cColAccess2].dwStatus == DBSTATUS_E_DOESNOTEXIST);

	//Compare First All Valid Columns
	TESTC(RowObjectA.CompareColAccess(cColAccess, &rgColInvalid[1], FIRST_ROW, pTable()));

	//Compare Second All Valid Columns
	//TODO: Some providers may not be able to obtain the data a second time (accessorder).
	//This will need to be changed once the spec is clear on this issue...
	TESTC(RowObjectA.CompareColAccess(cColAccess2, &rgColInvalid[1 + cColAccess + 2], FIRST_ROW, pTable()));

CLEANUP:
	FreeColAccess(cColAccess, rgColAccess);
	FreeColAccess(cColAccess2, rgColAccess2);
	SAFE_FREE(pData);
	SAFE_FREE(pData2);
	TRETURN
}
// }} TCW_VAR_PROTOTYPE_END

// {{ TCW_VAR_PROTOTYPE(14)
//*-----------------------------------------------------------------------
// @mfunc Vectors - All non-existent columns - DB_E_ERRORSOCCURRED
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCIRow_GetColumns::Variation_14()
{
	TBEGIN
	DBORDINAL i,cColInvalid = 0;
	DBCOLUMNACCESS* rgColInvalid = NULL;
	void* pData = NULL;

	//Obtain a row object
	CRowObject RowObjectA;
	TESTC_(GetRowObject(FIRST_ROW, &RowObjectA), S_OK);

	//Create the ColAccess Structures (for all columns)...
	TESTC_(RowObjectA.CreateColAccess(&cColInvalid, &rgColInvalid, &pData, NULL, ALL_COLS_BOUND, BLOB_LONG),S_OK);

	//Now replace the Array with (unique/nonexistent) columns
	for(i=0; i<cColInvalid; i++)
	{
		//Create a unique ColID name
		TESTC_(CreateUniqueDBID(&rgColInvalid[i].columnid),S_OK);
	}

	//IRow::GetColumns
	TESTC_(RowObjectA.GetColumns(cColInvalid, rgColInvalid),DB_E_ERRORSOCCURRED);

	//Verify Status'
	for(i=0; i<cColInvalid; i++)
		TESTC(rgColInvalid[i].dwStatus == DBSTATUS_E_DOESNOTEXIST);

CLEANUP:
	FreeColAccess(cColInvalid, rgColInvalid);
	SAFE_FREE(pData);
	TRETURN
}
// }} TCW_VAR_PROTOTYPE_END

// {{ TCW_VAR_PROTOTYPE(15)
//*-----------------------------------------------------------------------
// @mfunc Vectors - No Vector Columns - S_OK
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCIRow_GetColumns::Variation_15()
{
	TBEGIN

	//Loop through all the rows in the rowset, verify the columns...
	TESTC(VerifyGetColumnsAllRows(NULL, NOVECTOR_COLS_BOUND));

CLEANUP:
	TRETURN
}
// }} TCW_VAR_PROTOTYPE_END

// {{ TCW_VAR_PROTOTYPE(16)
//*-----------------------------------------------------------------------
// @mfunc Vectors - No Vectors and Non-Existent Columns - DB_E_ERRORSOCCURRED
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCIRow_GetColumns::Variation_16()
{
	TBEGIN
	DBORDINAL i,cColInvalid = 0;
	DBCOLUMNACCESS* rgColInvalid = NULL;
	void* pData = NULL;

	//Obtain a row object
	CRowObject RowObjectA;
	TESTC_(GetRowObject(FIRST_ROW, &RowObjectA), S_OK);

	//Create the ColAccess Structures (for all columns)...
	TESTC_(RowObjectA.CreateColAccess(&cColInvalid, &rgColInvalid, &pData, NULL, NOVECTOR_COLS_BOUND, BLOB_LONG),S_OK);

	//Now replace the Array with (unique/nonexistent) columns
	for(i=0; i<cColInvalid; i++)
	{
		//Create a unique ColID name
		TESTC_(CreateUniqueDBID(&rgColInvalid[i].columnid),S_OK);
	}

	//IRow::GetColumns
	TESTC_(RowObjectA.GetColumns(cColInvalid, rgColInvalid),DB_E_ERRORSOCCURRED);

	//Verify Status'
	for(i=0; i<cColInvalid; i++)
		TESTC(rgColInvalid[i].dwStatus == DBSTATUS_E_DOESNOTEXIST);

CLEANUP:
	FreeColAccess(cColInvalid, rgColInvalid);
	SAFE_FREE(pData);
	TRETURN
}
// }} TCW_VAR_PROTOTYPE_END

// {{ TCW_VAR_PROTOTYPE(17)
//*-----------------------------------------------------------------------
// @mfunc Vectors - Only Vector Columns - S_OK
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCIRow_GetColumns::Variation_17()
{
	TBEGIN

	//Loop through all the rows in the rowset, verify the columns...
	TESTC(VerifyGetColumnsAllRows(NULL, VECTOR_COLS_BOUND));

CLEANUP:
	TRETURN
}
// }} TCW_VAR_PROTOTYPE_END

// {{ TCW_VAR_PROTOTYPE(18)
//*-----------------------------------------------------------------------
// @mfunc Vectors - Only Non-Existent Vector Columns - DB_E_ERRORSOCCURRED
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCIRow_GetColumns::Variation_18()
{
	TBEGIN
	DBORDINAL i,cColInvalid = 0;
	DBCOLUMNACCESS* rgColInvalid = NULL;
	void* pData = NULL;

	//Obtain a row object
	CRowObject RowObjectA;
	TESTC_(GetRowObject(FIRST_ROW, &RowObjectA), S_OK);

	//Create the ColAccess Structures (for all columns)...
	TESTC_(RowObjectA.CreateColAccess(&cColInvalid, &rgColInvalid, &pData, NULL, VECTOR_COLS_BOUND),S_OK);

	//Now replace the Array with (unique/nonexistent) columns
	for(i=0; i<cColInvalid; i++)
	{
		//Create a unique ColID name
		TESTC_(CreateUniqueDBID(&rgColInvalid[i].columnid),S_OK);
	}

	//IRow::GetColumns
	TESTC_(RowObjectA.GetColumns(cColInvalid, rgColInvalid), cColInvalid ? DB_E_ERRORSOCCURRED : S_OK);

	//Verify Status'
	for(i=0; i<cColInvalid; i++)
		TESTC(rgColInvalid[i].dwStatus == DBSTATUS_E_DOESNOTEXIST);

CLEANUP:
	FreeColAccess(cColInvalid, rgColInvalid);
	SAFE_FREE(pData);
	TRETURN
}
// }} TCW_VAR_PROTOTYPE_END

// {{ TCW_VAR_PROTOTYPE(19)
//*-----------------------------------------------------------------------
// @mfunc Vectors - Valid Vectors and Non-Existent Columns - DB_S_ERRORSOCCURRED
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCIRow_GetColumns::Variation_19()
{
	TBEGIN
	DBORDINAL i,cColInvalid = 0;
	DBCOLUMNACCESS* rgColInvalid = NULL;
	void* pData = NULL;
	ULONG cNonVectors = 0;
	HRESULT hrExpected = S_OK;

	//Obtain a row object
	CRowObject RowObjectA;
	TESTC_(GetRowObject(FIRST_ROW, &RowObjectA), S_OK);

	//Create the ColAccess Structures (for all columns)...
	TESTC_(RowObjectA.CreateColAccess(&cColInvalid, &rgColInvalid, &pData, NULL, ALL_COLS_BOUND, BLOB_LONG),S_OK);

	//Now for all non-vectors, create a new invalid colid
	for(i=0; i<cColInvalid; i++)
	{
		//Create a unique ColID name (for all non-vectors)
		if(!(rgColInvalid[i].wType & DBTYPE_VECTOR))
		{
			TESTC_(CreateUniqueDBID(&rgColInvalid[i].columnid),S_OK);
			cNonVectors++;
		}
	}

	if(cNonVectors)
		hrExpected = (cColInvalid == cNonVectors) ? DB_E_ERRORSOCCURRED : DB_S_ERRORSOCCURRED;

	//IRow::GetColumns
	TESTC_(RowObjectA.GetColumns(cColInvalid, rgColInvalid), hrExpected);

	//Verify Status'
	for(i=0; i<cColInvalid; i++)
	{
		if(rgColInvalid[i].wType & DBTYPE_VECTOR)
		{
			TESTC(rgColInvalid[i].dwStatus == DBSTATUS_S_OK || rgColInvalid[i].dwStatus == DBSTATUS_S_ISNULL);
			TESTC(RowObjectA.CompareColAccess(1, &rgColInvalid[i], FIRST_ROW, pTable()));
		}
		else
		{
			//Only non-vectors where changed to non-existent columnids
			TESTC(rgColInvalid[i].dwStatus == DBSTATUS_E_DOESNOTEXIST);
		}
	}

CLEANUP:
	FreeColAccess(cColInvalid, rgColInvalid);
	SAFE_FREE(pData);
	TRETURN
}
// }} TCW_VAR_PROTOTYPE_END

// {{ TCW_VAR_PROTOTYPE(20)
//*-----------------------------------------------------------------------
// @mfunc Vectors - Valid Non-Vectors and Non-Existent Vector Columns - DB_S_ERRORSOCCURRED
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCIRow_GetColumns::Variation_20()
{
	TBEGIN
	DBORDINAL i,cColInvalid = 0;
	DBCOLUMNACCESS* rgColInvalid = NULL;
	void* pData = NULL;
	ULONG cVectors = 0;
	HRESULT hrExpected = S_OK;

	//Obtain a row object
	CRowObject RowObjectA;
	TESTC_(GetRowObject(FIRST_ROW, &RowObjectA), S_OK);

	//Create the ColAccess Structures (for all columns)...
	TESTC_(RowObjectA.CreateColAccess(&cColInvalid, &rgColInvalid, &pData, NULL, ALL_COLS_BOUND, BLOB_LONG),S_OK);

	//Now for all non-vectors, create a new invalid colid
	for(i=0; i<cColInvalid; i++)
	{
		//Create a unique ColID name (for all non-vectors)
		if(rgColInvalid[i].wType & DBTYPE_VECTOR)
		{
			TESTC_(CreateUniqueDBID(&rgColInvalid[i].columnid),S_OK);
			cVectors++;
		}
	}

	if(cVectors)
		hrExpected = (cColInvalid == cVectors) ? DB_E_ERRORSOCCURRED : DB_S_ERRORSOCCURRED;

	//IRow::GetColumns
	TESTC_(RowObjectA.GetColumns(cColInvalid, rgColInvalid), hrExpected);

	//Verify Status'
	for(i=0; i<cColInvalid; i++)
	{
		if(rgColInvalid[i].wType & DBTYPE_VECTOR)
		{
			//Only vectors where changed to non-existent columnids
			TESTC(rgColInvalid[i].dwStatus == DBSTATUS_E_DOESNOTEXIST);
		}
		else
		{
			TESTC(rgColInvalid[i].dwStatus == DBSTATUS_S_OK || rgColInvalid[i].dwStatus == DBSTATUS_S_ISNULL);
			TESTC(RowObjectA.CompareColAccess(1, &rgColInvalid[i], FIRST_ROW, pTable()));
		}
	}

CLEANUP:
	FreeColAccess(cColInvalid, rgColInvalid);
	SAFE_FREE(pData);
	TRETURN
}
// }} TCW_VAR_PROTOTYPE_END

// {{ TCW_VAR_PROTOTYPE(21)
//*-----------------------------------------------------------------------
// @mfunc Empty
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCIRow_GetColumns::Variation_21()
{
	return TEST_SKIPPED;
}
// }} TCW_VAR_PROTOTYPE_END

// {{ TCW_VAR_PROTOTYPE(22)
//*-----------------------------------------------------------------------
// @mfunc Boundary - 0 columns -[0, NULL] and [0, valid]  no-op
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCIRow_GetColumns::Variation_22()
{
	TBEGIN

	//GetColumns - with (0, NULL)
	TESTC(VerifyGetColumnsAllRows(NULL, USE_COLS_TO_BIND_ARRAY, BLOB_LONG, FORWARD,
				NO_COLS_BY_REF,	DBTYPE_EMPTY, 0, NULL));

	//GetColumns - with (0, valid)
	TESTC_(m_pCRowObject->GetColumns(0, INVALID(DBCOLUMNACCESS*)), S_OK);

CLEANUP:
	TRETURN
}
// }} TCW_VAR_PROTOTYPE_END

// {{ TCW_VAR_PROTOTYPE(23)
//*-----------------------------------------------------------------------
// @mfunc Boundary - [Valid, NULL] - E_INVALIDARG
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCIRow_GetColumns::Variation_23()
{
	TBEGIN

	//GetColumns - with (Valid, NULL)- E_INVALIDARG
	TESTC_(m_pCRowObject->GetColumns(5, NULL), E_INVALIDARG);

CLEANUP:
	TRETURN
}
// }} TCW_VAR_PROTOTYPE_END

// {{ TCW_VAR_PROTOTYPE(24)
//*-----------------------------------------------------------------------
// @mfunc Empty
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCIRow_GetColumns::Variation_24()
{
	return TEST_SKIPPED;
}
// }} TCW_VAR_PROTOTYPE_END

// {{ TCW_VAR_PROTOTYPE(25)
//*-----------------------------------------------------------------------
// @mfunc Boundary - columnid - all valid dbkinds
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCIRow_GetColumns::Variation_25()
{
	TBEGIN
	DBORDINAL i,cColInvalid = 0;
	DBCOLUMNACCESS* rgColInvalid = NULL;
	void* pData = NULL;
	ULONG cNonVectors = 0;
	HRESULT hrExpected = S_OK;

	//Obtain a row object
	CRowObject RowObjectA;
	TESTC_(GetRowObject(FIRST_ROW, &RowObjectA), S_OK);

	//Create the ColAccess Structures (for all columns)...
	TESTC_(RowObjectA.CreateColAccess(&cColInvalid, &rgColInvalid, &pData, NULL, ALL_COLS_BOUND, BLOB_LONG),S_OK);

	//Loop through all columns
	for(i=0; i<cColInvalid; i++)
	{
		DBCOLUMNACCESS* pColAccess = &rgColInvalid[i];

		//Valid DBKINDs are DBKIND_GUID_NAME(0) through DBKIND_GUID(6)
		//So create values from 0 - 6 (inclusive- ie: plus 1)...
		ReleaseDBID(&pColAccess->columnid, FALSE/*fDrop*/);
		pColAccess->columnid.eKind = (ULONG)i % (DBKIND_GUID+1);

		//Now Create a unique colid for this type...
		TESTC_(CreateUniqueDBID(&pColAccess->columnid),S_OK);
	}

	//IRow::GetColumns
	TESTC_(RowObjectA.GetColumns(cColInvalid, rgColInvalid), cColInvalid ? DB_E_ERRORSOCCURRED : S_OK);

	//Verify Status'
	for(i=0; i<cColInvalid; i++)
	{
		//All columns were fabricated guids, (so we could test remoting with all column types)
		TESTC(rgColInvalid[i].dwStatus == DBSTATUS_E_DOESNOTEXIST);
	}

CLEANUP:
	FreeColAccess(cColInvalid, rgColInvalid);
	SAFE_FREE(pData);
	TRETURN
}
// }} TCW_VAR_PROTOTYPE_END

// {{ TCW_VAR_PROTOTYPE(26)
//*-----------------------------------------------------------------------
// @mfunc Boundary - columnid - invalid dbkinds
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCIRow_GetColumns::Variation_26()
{
	TBEGIN
	DBORDINAL i,cColInvalid = 0;
	DBCOLUMNACCESS* rgColInvalid = NULL;
	void* pData = NULL;
	ULONG cNonVectors = 0;
	HRESULT hrExpected = S_OK;

	//Obtain a row object
	CRowObject RowObjectA;
	TESTC_(GetRowObject(FIRST_ROW, &RowObjectA), S_OK);

	//Create the ColAccess Structures (for all columns)...
	TESTC_(RowObjectA.CreateColAccess(&cColInvalid, &rgColInvalid, &pData, NULL, ALL_COLS_BOUND, BLOB_LONG),S_OK);

	//Loop through all columns
	for(i=0; i<cColInvalid; i++)
	{
		DBCOLUMNACCESS* pColAccess = &rgColInvalid[i];

		//Valid DBKINDs are DBKIND_GUID_NAME(0) through DBKIND_GUID(6)
		//So create values from 7...
		ReleaseDBID(&pColAccess->columnid, FALSE/*fDrop*/);
		pColAccess->columnid.eKind = DBKIND_GUID+1;
	}

	//IRow::GetColumns
	TESTC_(RowObjectA.GetColumns(cColInvalid, rgColInvalid), cColInvalid ? DB_E_ERRORSOCCURRED : S_OK);

	//Verify Status'
	for(i=0; i<cColInvalid; i++)
	{
		//All columns were fabricated guids, (so we could test remoting with all column types)
		TESTC(rgColInvalid[i].dwStatus == DBSTATUS_E_DOESNOTEXIST);
	}

CLEANUP:
	FreeColAccess(cColInvalid, rgColInvalid);
	SAFE_FREE(pData);
	TRETURN
}
// }} TCW_VAR_PROTOTYPE_END

// {{ TCW_VAR_PROTOTYPE(27)
//*-----------------------------------------------------------------------
// @mfunc Boundary - columnid - invalid [but close to original] dbkinds
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCIRow_GetColumns::Variation_27()
{
	TBEGIN
	DBORDINAL iCol,cColInvalid = 0;
	DBCOLUMNACCESS* rgColInvalid = NULL;
	void* pData = NULL;
	ULONG cNonVectors = 0;
	HRESULT hrExpected = S_OK;

	//Obtain a row object
	CRowObject RowObjectA;
	TESTC_(GetRowObject(FIRST_ROW, &RowObjectA), S_OK);

	//Create the ColAccess Structures (for all columns)...
	TESTC_(RowObjectA.CreateColAccess(&cColInvalid, &rgColInvalid, &pData, NULL, ALL_COLS_BOUND, BLOB_LONG),S_OK);

	//Loop through all columns
	for(iCol=0; iCol<cColInvalid; iCol++)
	{
		DBID* pColumnID = &rgColInvalid[iCol].columnid;

		//The problem is that for multipart-DBIDs (two part naming), the provider may only validate
		//one and allow to the the other to fall through.
		switch(pColumnID->eKind)
		{
			case DBKIND_GUID_NAME:
			case DBKIND_PGUID_NAME:
			{
				GUID guid;

				//Create a "unique" string
				SAFE_FREE(pColumnID->uName.pwszName);

				//For every other "name" column - well use NULL
				if(iCol%2)
				{
					TESTC_(CoCreateGuid(&guid),S_OK);
					TESTC_(StringFromCLSID(guid, &pColumnID->uName.pwszName),S_OK);
				}
				break;
			}

			default:
			{
				//Otherwise just create a completely unique name...
				//For two-part it changes the GUID, so all we really have left is to verify
				//that only changing the name is caught...
				TESTC_(CreateUniqueDBID(pColumnID, TRUE/*fInitialize*/),S_OK);
				break;
			}
		};
	}

	//IRow::GetColumns
	TESTC_(RowObjectA.GetColumns(cColInvalid, rgColInvalid), cColInvalid ? DB_E_ERRORSOCCURRED : S_OK);

	//Verify Status'
	for(iCol=0; iCol<cColInvalid; iCol++)
	{
		//All columns were fabricated guids, (so we could test remoting with all column types)
		TESTC(rgColInvalid[iCol].dwStatus == DBSTATUS_E_DOESNOTEXIST);
	}

CLEANUP:
	FreeColAccess(cColInvalid, rgColInvalid);
	SAFE_FREE(pData);
	TRETURN
}
// }} TCW_VAR_PROTOTYPE_END

// {{ TCW_VAR_PROTOTYPE(28)
//*-----------------------------------------------------------------------
// @mfunc Boundary - cbMaxLen - ignored for fixed length types
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCIRow_GetColumns::Variation_28()
{
	TBEGIN
	DBORDINAL i,cColAccess = 0;
	DBCOLUMNACCESS* rgColAccess = NULL;
	void* pData = NULL;

	//Obtain a row object
	CRowObject RowObjectA;
	TESTC_(GetRowObject(FIRST_ROW, &RowObjectA), S_OK);

	//Create the ColAccess Structures (for all columns)...
	TESTC_(RowObjectA.CreateColAccess(&cColAccess, &rgColAccess, &pData, NULL, ALL_COLS_BOUND, BLOB_LONG),S_OK);

	//Now make sure the provider ignores cbMaxLen for fixed length types
	for(i=0; i<cColAccess; i++)
	{
		DBCOLUMNACCESS* pColAccess = &rgColAccess[i];

		//The provider is supposed to ignore cbMaxLen for Fixed Length data types,
		//as well as the modifiers (DBTYPE_BYREF and DBTYPE_ARRAY and DBTYPE_VECTOR)
		if(IsFixedLength(pColAccess->wType) ||
			(pColAccess->wType & (DBTYPE_BYREF|DBTYPE_ARRAY|DBTYPE_VECTOR)))
		{
			//NOTE: We want to vary this value, since -1 (ULONG_MAX) might cause problems if there
			//using this value for allocations, and 0 might cause problems is using for remoting
			//for the next location in the buffer, etc.  We also want to vary the value since the
			//proivder / remoting might have special checks against fixed values for protection...
			pColAccess->cbMaxLen = i ? (-1/*ULONG_MAX*//i) : 0; //Protect against divide by 0
		}
	}

	//IRow::GetColumns
	TESTC_(RowObjectA.GetColumns(cColAccess, rgColAccess),S_OK);
	//Compare Data for this row object
	TESTC(RowObjectA.CompareColAccess(cColAccess, rgColAccess, FIRST_ROW, pTable()));

CLEANUP:
	FreeColAccess(cColAccess, rgColAccess);
	SAFE_FREE(pData);
	TRETURN
}
// }} TCW_VAR_PROTOTYPE_END

// {{ TCW_VAR_PROTOTYPE(29)
//*-----------------------------------------------------------------------
// @mfunc Boundary - cbMaxLen - DBSTATUS_S_TRUNCATION
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCIRow_GetColumns::Variation_29()
{
	TBEGIN
	DBORDINAL i,cColAccess = 0;
	DBCOLUMNACCESS* rgColAccess = NULL;
	void* pData = NULL;
	ULONG cTruncated = 0;
	HRESULT hrExpected = S_OK;

	//Obtain a row object
	CRowObject RowObjectA;
	TESTC_(GetRowObject(FIRST_ROW, &RowObjectA), S_OK);

	//Create the ColAccess Structures (for all columns)...
	TESTC_(RowObjectA.CreateColAccess(&cColAccess, &rgColAccess, &pData, NULL, ALL_COLS_BOUND, BLOB_LONG),S_OK);

	//Loop through all columns
	for(i=0; i<cColAccess; i++)
	{
		DBCOLUMNACCESS* pColAccess = &rgColAccess[i];

		//Truncate all variable string length types...
		if(IsFixedLength(pColAccess->wType))
		{
			//NOTE: cbMaxLength is ignored for fixed length types...
			pColAccess->cbMaxLen = 0;
		}
		else
		{
			//NOTE: We want to vary this value, since it may have different effects on different
			//types and setting it to 0 may go through a different code path than ~0, etc...
			pColAccess->cbMaxLen = cTruncated;
			if(pColAccess->wType == DBTYPE_STR || pColAccess->wType == DBTYPE_WSTR)
			{
				//We only increment if a string, since we want the first string data
				//to have a 0 byte cbMaxLen (not enough for a NULL terminator)
				cTruncated++;

				//NOTE: Truncation is considered a "warning" and not an error.  So normally you
				//would expect S_OK to be returned, but since we set the first Variable Length
				//column to cbMaxLen=0, this should be DataOverFlow, since their is not even enough
				//room for the NULL terminator, so if the provider actually returns "Truncation" the
				//consumer would crash since their is not null terminator, and would be whatever was left
				//in the buffer...
				hrExpected = (cTruncated==cColAccess) ? DB_E_ERRORSOCCURRED : DB_S_ERRORSOCCURRED;
			}
		}
	}

	//IRow::GetColumns
	TESTC_(RowObjectA.GetColumns(cColAccess, rgColAccess), hrExpected);

	//Verify the returned status, and data...
	for(i=0; i<cColAccess; i++)
	{
		DBCOLUMNACCESS* pColAccess = &rgColAccess[i];

		//Verify the Status
		switch(pColAccess->dwStatus)
		{
			case DBSTATUS_S_OK:
				//NOTE: cbMaxLength is ignored for fixed length types...
				if(!IsFixedLength(pColAccess->wType))
					TESTC(pColAccess->cbDataLen <= pColAccess->cbMaxLen);
				break;

			case DBSTATUS_S_ISNULL:
				//NULL data is an exception since it doesn't matter what cbMaxLen was...
				break;

			case DBSTATUS_S_TRUNCATED:
				//NOTE: cbMaxLength is ignored for fixed length types...
				//NOTE: We have to check "cbMaxLen" since cbDataLen is the "true" untruncated
				//length of the actual data - if there was engouh room...
				TESTC(!IsFixedLength(pColAccess->wType));
				TESTC(pColAccess->cbDataLen >= pColAccess->cbMaxLen);

				//Make sure there was enough room for the _entire_ NULL Terminator
				//(ie: 2 bytes for the WCHAR NULL terminator)
				if(pColAccess->wType == DBTYPE_STR)
					TESTC(pColAccess->cbMaxLen >= sizeof(CHAR));
				if(pColAccess->wType == DBTYPE_WSTR)
					TESTC(pColAccess->cbMaxLen >= sizeof(WCHAR));
				break;

			case DBSTATUS_E_DATAOVERFLOW:
				//NOTE: Truncation is considered a "warning" and not an error.  So normally you
				//would expect S_OK to be returned, but since we set the first Variable Length
				//column to cbMaxLen=0, this should be DataOverFlow, since their is not even enough
				//room for the NULL terminator, so if the provider actually returns "Truncation" the
				//consumer would crash since their is not null terminator, and would be whatever was left
				//in the buffer...

				//NOTE: We have to check "cbMaxLen" since cbDataLen is the "true" untruncated
				//length of the actual data - if there was engouh room...
				TESTC(!IsFixedLength(pColAccess->wType));
				TESTC(pColAccess->cbMaxLen == 0 ||
					(pColAccess->wType == DBTYPE_WSTR && pColAccess->cbMaxLen<sizeof(WCHAR)) );

				//Can't compare data in this case...
				continue;
				break;

			default:
				TESTC(FALSE);	//Not an appropiate status...
		};

		//Compare Data for this column
		TESTC(RowObjectA.CompareColAccess(1, pColAccess, FIRST_ROW, pTable()));
	}

CLEANUP:
	FreeColAccess(cColAccess, rgColAccess);
	SAFE_FREE(pData);
	TRETURN
}
// }} TCW_VAR_PROTOTYPE_END

// {{ TCW_VAR_PROTOTYPE(30)
//*-----------------------------------------------------------------------
// @mfunc Boundary - cbMaxLen - invalid
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCIRow_GetColumns::Variation_30()
{
	// TO DO:  Add your own code here
	return TRUE;
}
// }} TCW_VAR_PROTOTYPE_END

// {{ TCW_VAR_PROTOTYPE(31)
//*-----------------------------------------------------------------------
// @mfunc Empty
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCIRow_GetColumns::Variation_31()
{
	return TEST_SKIPPED;
}
// }} TCW_VAR_PROTOTYPE_END

// {{ TCW_VAR_PROTOTYPE(32)
//*-----------------------------------------------------------------------
// @mfunc Boundary - wType - all valid types and modifieres
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCIRow_GetColumns::Variation_32()
{
	// TO DO:  Add your own code here
	return TRUE;
}
// }} TCW_VAR_PROTOTYPE_END

// {{ TCW_VAR_PROTOTYPE(33)
//*-----------------------------------------------------------------------
// @mfunc Boundary - wType - invalid types and invalid type modifiers
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCIRow_GetColumns::Variation_33()
{
	TBEGIN
	DBORDINAL i,cColAccess = 0;
	DBCOLUMNACCESS* rgColAccess = NULL;
	void* pData = NULL;
	ULONG cInvalid = 0;
	HRESULT hr = S_OK;

	//Obtain a row object
	CRowObject RowObjectA;
	TESTC_(GetRowObject(FIRST_ROW, &RowObjectA), S_OK);

	//Create the ColAccess Structures (for all columns)...
	//NOTE: We will bind all columns as DBTYPE_VECTOR,
	//we have to do this ahead of time so that all the offsets and buffer sizes will be large
	//enough, we can't juist spin through the types later and change them since the buffer
	//won't have enough room, and will be pointing to the wrong spots...
	TESTC_(RowObjectA.CreateColAccess(&cColAccess, &rgColAccess, &pData, NULL,
		ALL_COLS_BOUND, BLOB_LONG, FORWARD, NO_COLS_BY_REF, DBTYPE_VECTOR),S_OK);

	//Loop through all (original) column access structures
	//Since the above already put on DBTYPE_VECTOR we need to know the type before doing this...
	for(i=0; i<RowObjectA.m_cColAccess; i++)
	{
		DBCOLUMNACCESS* pColAccess = &RowObjectA.m_rgColAccess[i];

		//Although we are trying for an error senario, (not all types converted to DBTYPE_VECTOR)
		//The provider may actually support this conversion.  We can't just specifiy
		//an invalid type, since that will more than likely be caught way up front, and not actually
		//hit the conversion code we are looking for (for example: in remoting an invalid type
		//is not even sent the to the provider, whereas an unsupported conversion goes all
		//the way across and will fail on return, this is what we want).

		//See if this is a problem converting for the provider
		TEST2C_(hr = RowObjectA.pIConvertType()->CanConvert(pColAccess->wType, pColAccess->wType | DBTYPE_VECTOR, DBCONVERTFLAGS_COLUMN),S_OK,S_FALSE);
		if(hr != S_OK)
			cInvalid++;
	}

	//IRow::GetColumns
	TEST3C_(hr = RowObjectA.GetColumns(cColAccess, rgColAccess), S_OK, DB_S_ERRORSOCCURRED, DB_E_ERRORSOCCURRED);

	//Possibilities:
	//1.  Everything can be converted fine (cInvalid==0)	- S_OK
	//2.  Some column could be converted but not all		- DB_S_ERROROCCURRED
	//3.  All columns coulnd not be converted				- DB_E_ERRORSOCCURRED
	//The exception is that some column even though indicated could not be converted, could still
	//be convergted if the status was ISNULL - since now conversion is required for this senario...
	//Thats why we allow S_OK in all the following senarios...
	if(cInvalid == 0)
		TESTC_(hr, S_OK);
	if(cInvalid < cColAccess)
		TEST2C_(hr, S_OK, DB_S_ERRORSOCCURRED);
	if(cInvalid && cInvalid == cColAccess)
		TEST3C_(hr, S_OK, DB_S_ERRORSOCCURRED, DB_E_ERRORSOCCURRED);

	//Loop through all columns
	for(i=0; i<cColAccess; i++)
	{
		DBCOLUMNACCESS* pColAccess = &rgColAccess[i];

		//Verify the result
		if(pColAccess->dwStatus == DBSTATUS_S_OK || pColAccess->dwStatus == DBSTATUS_S_ISNULL)
		{
			//Verify the data returned (successfully converted this)
			TESTC(RowObjectA.CompareColAccess(1, pColAccess, FIRST_ROW, pTable()));
		}
		else
		{
			TESTC(pColAccess->dwStatus == DBSTATUS_E_CANTCONVERTVALUE);
		}
	}

CLEANUP:
	FreeColAccess(cColAccess, rgColAccess);
	SAFE_FREE(pData);
	TRETURN
}
// }} TCW_VAR_PROTOTYPE_END

// {{ TCW_VAR_PROTOTYPE(34)
//*-----------------------------------------------------------------------
// @mfunc Empty
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCIRow_GetColumns::Variation_34()
{
	return TEST_SKIPPED;
}
// }} TCW_VAR_PROTOTYPE_END

// {{ TCW_VAR_PROTOTYPE(35)
//*-----------------------------------------------------------------------
// @mfunc Boundary - bPrecision - make sure ignored on input for all types, except NUMERIC.
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCIRow_GetColumns::Variation_35()
{
	// TO DO:  Add your own code here
	return TRUE;
}
// }} TCW_VAR_PROTOTYPE_END

// {{ TCW_VAR_PROTOTYPE(36)
//*-----------------------------------------------------------------------
// @mfunc Boundary - bScale - make sure ignored on input for all types, except NUMERIC.
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCIRow_GetColumns::Variation_36()
{
	// TO DO:  Add your own code here
	return TRUE;
}
// }} TCW_VAR_PROTOTYPE_END

// {{ TCW_VAR_PROTOTYPE(37)
//*-----------------------------------------------------------------------
// @mfunc Boundary - Output Only - make sure cbDataLen, dwStatus, dwReserverd are ignored on input
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCIRow_GetColumns::Variation_37()
{
	TBEGIN
	DBORDINAL i,cColAccess = 0;
	DBCOLUMNACCESS* rgColAccess = NULL;
	void* pData = NULL;

	//Obtain a row object
	CRowObject RowObjectA;
	TESTC_(GetRowObject(FIRST_ROW, &RowObjectA), S_OK);

	//Create the ColAccess Structures (for all columns)...
	TESTC_(RowObjectA.CreateColAccess(&cColAccess, &rgColAccess, &pData, NULL, ALL_COLS_BOUND, BLOB_LONG),S_OK);

	//Loop through all columns
	for(i=0; i<cColAccess; i++)
	{
		DBCOLUMNACCESS* pColAccess = &rgColAccess[i];

		//Set input params that are supposed to be ignored to a "known" value
		pColAccess->dwStatus	= DBSTATUS_S_OK + (ULONG)i + 1; //Everything beyond S_OK is interesting
		pColAccess->cbDataLen	= (-1) - i;
		pColAccess->dwReserved	= i;
	}

	//IRow::GetColumns
	TESTC_(RowObjectA.GetColumns(cColAccess, rgColAccess), S_OK);

	//Compare Data for this column
	TESTC(RowObjectA.CompareColAccess(cColAccess, rgColAccess, FIRST_ROW, pTable()));

CLEANUP:
	FreeColAccess(cColAccess, rgColAccess);
	SAFE_FREE(pData);
	TRETURN
}
// }} TCW_VAR_PROTOTYPE_END

// {{ TCW_VAR_PROTOTYPE(38)
//*-----------------------------------------------------------------------
// @mfunc Boundary - Input - Make sure all pointers and input args are not changed on output, pData pointer, columnid [including all union pointers], cbMaxLen, dwReserved, wType.
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCIRow_GetColumns::Variation_38()
{
	TBEGIN
	DBORDINAL i,cColAccess = 0;
	DBCOLUMNACCESS* rgColAccess = NULL;
	DBCOLUMNACCESS* rgColAccessCopy = NULL;
	void* pData = NULL;

	//Obtain a row object
	CRowObject RowObjectA;
	TESTC_(GetRowObject(FIRST_ROW, &RowObjectA), S_OK);

	//Create the ColAccess Structures (for all columns)...
	TESTC_(RowObjectA.CreateColAccess(&cColAccess, &rgColAccess, &pData, NULL, ALL_COLS_BOUND, BLOB_LONG),S_OK);

	//Make more interesting data for some of the items
	for(i=0; i<cColAccess; i++)
	{
		DBCOLUMNACCESS* pColAccess = &rgColAccess[i];

		//Every other column (so some succeed)
		if(i%2 == 0)
		{
			//columnid
			ReleaseDBID(&pColAccess->columnid, FALSE/*fDrop*/);
			pColAccess->columnid.eKind = (ULONG)i % (DBKIND_GUID+1);
			TESTC_(CreateUniqueDBID(&pColAccess->columnid),S_OK);
		}

		//The consumer might have used this reserver flag for internal storage,
		//so the provider should not be looking at it or setting it...
		pColAccess->dwReserved = i;
	}

	//Make a "snapshot" copy to compare against
	SAFE_ALLOC(rgColAccessCopy, DBCOLUMNACCESS, cColAccess);
	memcpy(rgColAccessCopy, rgColAccess, (size_t)(cColAccess*sizeof(DBCOLUMNACCESS)));

	//IRow::GetColumns
	TESTC_(RowObjectA.GetColumns(cColAccess, rgColAccess), cColAccess ? DB_S_ERRORSOCCURRED : S_OK);

	//Make more interesting data for some of the items
	for(i=0; i<cColAccess; i++)
	{
		DBCOLUMNACCESS* pColAccess		= &rgColAccess[i];
		DBCOLUMNACCESS* pColAccessCopy	= &rgColAccessCopy[i];

		//Verify non-output items have not changed from inputs
		TESTC(memcmp(&pColAccess->columnid, &pColAccessCopy->columnid, sizeof(DBID))==0);
		TESTC(pColAccess->pData			== pColAccessCopy->pData);
		TESTC(pColAccess->cbMaxLen		== pColAccessCopy->cbMaxLen);
		TESTC(pColAccess->dwReserved	== pColAccessCopy->dwReserved || pColAccess->dwReserved == 0);
		TESTC(pColAccess->wType			== pColAccessCopy->wType);
		TESTC(pColAccess->bPrecision	== pColAccessCopy->bPrecision);
		TESTC(pColAccess->bScale		== pColAccessCopy->bScale);

		//Compare Data for this column
		if(i%2 == 0)
		{
			TESTC(pColAccess->dwStatus == DBSTATUS_E_DOESNOTEXIST);
		}
		else
		{
			TESTC(RowObjectA.CompareColAccess(1, pColAccess, FIRST_ROW, pTable()));
		}
	}

CLEANUP:
	FreeColAccess(cColAccess, rgColAccess);
	SAFE_FREE(rgColAccessCopy);
	SAFE_FREE(pData);
	TRETURN
}
// }} TCW_VAR_PROTOTYPE_END

BOOL TCIRow_GetColumns::FindColumnDBTYPE_BYTES(DBSTATUS status, DBCOUNTITEM *pRowIndex, DBORDINAL *pColIndex)
{
	ASSERT(pRowIndex != NULL);
	ASSERT(pColIndex != NULL);

	DBORDINAL cColAccess = 0;
	DBCOLUMNACCESS* rgColAccess = NULL;
	void* pData = NULL;
	bool found = FALSE;

	DBCOUNTITEM rowCountInTable = m_pTable->GetRowsOnCTable();
	for (DBCOUNTITEM rowIndex = 1; rowIndex < rowCountInTable; ++rowIndex)
	{
		//Obtain a row object
		CRowObject RowObjectA;
		TESTC_(GetRowObject(rowIndex, &RowObjectA), S_OK);

		//Create the ColAccess Structures (for all columns)...
		TESTC_(RowObjectA.CreateColAccess(&cColAccess, &rgColAccess, &pData, NULL, ALL_COLS_BOUND, BLOB_LONG),S_OK);

		//IRow::GetColumns
		TESTC_(RowObjectA.GetColumns(cColAccess, rgColAccess), S_OK);

		// column 0. non-null, improperly aligned
		for (DBORDINAL colIndex = 0; colIndex < cColAccess; ++colIndex)
		{
			if ((rgColAccess[colIndex].dwStatus == status) && (rgColAccess[colIndex].wType == DBTYPE_BYTES))
			{
				*pRowIndex = rowIndex;
				*pColIndex = colIndex;
				found = TRUE;
				goto CLEANUP;
			}
		}

		FreeColAccess(cColAccess, rgColAccess);
		cColAccess = 0;
		rgColAccess = NULL;

		SAFE_FREE(pData);
		pData = NULL;
	}

CLEANUP:

	FreeColAccess(cColAccess, rgColAccess);
	SAFE_FREE(pData);

	return found;
}

int TCIRow_GetColumns::UnalignedBuferTest(DBSTATUS columnStatus)
{
	TBEGIN

	DBORDINAL cColAccess = 0;
	DBCOLUMNACCESS* rgColAccess = NULL;
	void* pData = NULL;
	BYTE* pDataUnaligned = NULL;
	CRowObject RowObjectA;

	DBCOUNTITEM rowIndex;
	DBORDINAL colIndex;

	BOOL found = FindColumnDBTYPE_BYTES(columnStatus, &rowIndex, &colIndex);
	if (!found)
	{
		TESTB = TEST_SKIPPED;
		goto CLEANUP;
	}

	TESTC_(GetRowObject(rowIndex, &RowObjectA), S_OK);
	TESTC_(RowObjectA.CreateColAccess(&cColAccess, &rgColAccess, &pData, NULL, ALL_COLS_BOUND, BLOB_LONG),S_OK);

	SAFE_ALLOC(pDataUnaligned, BYTE, rgColAccess[colIndex].cbMaxLen + 1);
	memset(pDataUnaligned, 0, (size_t)(rgColAccess[colIndex].cbMaxLen + 1));

	rgColAccess[colIndex].pData = pDataUnaligned + 1;

	TESTC_(RowObjectA.GetColumns(cColAccess, rgColAccess), S_OK);

	ASSERT(rgColAccess[colIndex].dwStatus == columnStatus);

CLEANUP:

	FreeColAccess(cColAccess, rgColAccess);
	SAFE_FREE(pData);
	SAFE_FREE(pDataUnaligned);
	TRETURN
}

// {{ TCW_VAR_PROTOTYPE(39)
//*-----------------------------------------------------------------------
// @mfunc Empty
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCIRow_GetColumns::Variation_39()
{
	//return UnalignedBuferTest(DBSTATUS_S_ISNULL);//Supply unaligned buffer for NULL bytes value
	return TEST_SKIPPED;
}
// }} TCW_VAR_PROTOTYPE_END

// {{ TCW_VAR_PROTOTYPE(40)
//*-----------------------------------------------------------------------
// @mfunc Supply unaligned buffer for non-NULL bytes value
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCIRow_GetColumns::Variation_40()
{
	return UnalignedBuferTest(DBSTATUS_S_OK);

}
// }} TCW_VAR_PROTOTYPE_END

// {{ TCW_VAR_PROTOTYPE(41)
//*-----------------------------------------------------------------------
// @mfunc Empty
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCIRow_GetColumns::Variation_41()
{
	return TEST_SKIPPED;
}
// }} TCW_VAR_PROTOTYPE_END

// {{ TCW_VAR_PROTOTYPE(42)
//*-----------------------------------------------------------------------
// @mfunc Empty
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCIRow_GetColumns::Variation_42()
{
	return TEST_SKIPPED;
}
// }} TCW_VAR_PROTOTYPE_END

// {{ TCW_VAR_PROTOTYPE(43)
//*-----------------------------------------------------------------------
// @mfunc Buffered Mode - All Columns - no BLOBs
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCIRow_GetColumns::Variation_43()
{
	TBEGIN

	//Create a buffered mode rowset
	CRowsetUpdate RowsetA;

	//Not all providers will support IRowsetUpdate
	TESTC_PROVIDER(RowsetA.CreateRowset()==S_OK);

	//Loop through all the rows in the rowset, verify the columns...
	TESTC(VerifyGetColumnsAllRows(&RowsetA, ALL_COLS_BOUND));

CLEANUP:
	TRETURN
}
// }} TCW_VAR_PROTOTYPE_END

// {{ TCW_VAR_PROTOTYPE(44)
//*-----------------------------------------------------------------------
// @mfunc Buffered Mode - All Columns - BLOBs
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCIRow_GetColumns::Variation_44()
{
	TBEGIN

	//Create a buffered mode rowset
	CRowsetUpdate RowsetA;

	//Not all providers will support IRowsetUpdate
	TESTC_PROVIDER(RowsetA.CreateRowset()==S_OK);

	//Loop through all the rows in the rowset, verify the columns...
	TESTC(VerifyGetColumnsAllRows(&RowsetA, ALL_COLS_BOUND, BLOB_LONG));

CLEANUP:
	TRETURN
}
// }} TCW_VAR_PROTOTYPE_END

// {{ TCW_VAR_PROTOTYPE(45)
//*-----------------------------------------------------------------------
// @mfunc Buffered Mode - All Columns - Just extra columns
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCIRow_GetColumns::Variation_45()
{
	TBEGIN
	DBORDINAL cColAccess = 0;
	DBCOLUMNACCESS* rgColAccess = NULL;
	void* pData = NULL;

	DBORDINAL cColumns = 0;
	DBORDINAL* rgColOrdinals = NULL;
	HRESULT hr = E_FAIL;

	//Create a buffered mode rowset
	CRowsetUpdate RowsetA;
	CRowObject RowObjectA;

	//Not all providers will support IRowsetUpdate
	TESTC_PROVIDER(RowsetA.CreateRowset()==S_OK);

	//Now create the row object.
	TESTC_(RowsetA.GetRowObject(FIRST_ROW, &RowObjectA), S_OK);

	//Obtain the just the Extra columns
	TEST2C_(hr = RowObjectA.GetExtraColumnInfo(&cColumns, NULL, NULL, &rgColOrdinals),S_OK,DB_E_NOSOURCEOBJECT);
	if(hr == DB_E_NOSOURCEOBJECT)
	{
		odtLog << "This provider does not support IRow::GetSourceRowset\n";
		TESTB = TEST_SKIPPED;
		goto CLEANUP;
	}

	//Create the ColAccess Structures for just the extra columns...
	TESTC_(RowObjectA.CreateColAccess(&cColAccess, &rgColAccess, &pData, NULL, ALL_COLS_BOUND, BLOB_LONG, FORWARD, NO_COLS_BY_REF, DBTYPE_EMPTY, cColumns, rgColOrdinals),S_OK);

	//IRow::GetColumns
	TESTC_(RowObjectA.GetColumns(cColAccess, rgColAccess),S_OK);

	//Compare Data for this row object
	TESTC(RowObjectA.CompareColAccess(cColAccess, rgColAccess, FIRST_ROW, pTable()));

CLEANUP:
	FreeColAccess(cColAccess, rgColAccess);
	SAFE_FREE(pData);
	SAFE_FREE(rgColOrdinals);
	TRETURN
}
// }} TCW_VAR_PROTOTYPE_END

// {{ TCW_VAR_PROTOTYPE(46)
//*-----------------------------------------------------------------------
// @mfunc Empty
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCIRow_GetColumns::Variation_46()
{
	return TEST_SKIPPED;
}
// }} TCW_VAR_PROTOTYPE_END

// {{ TCW_VAR_PROTOTYPE(47)
//*-----------------------------------------------------------------------
// @mfunc Aggregation - Command - > Row
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCIRow_GetColumns::Variation_47()
{
	TBEGIN
    CAggregate Aggregate;
	IUnknown* pIUnkInner = NULL;
	ULONG_PTR dwValue = 0;
	HRESULT hr = S_OK;

	CCommand CommandA;
	CommandA.SetProperty(DBPROP_IRow);

	//Create a command object
	TESTC_PROVIDER(CommandA.CreateCommand()==S_OK);

	//Try the invalid senario first... (asking for non-IUnknown)
	TESTC_(hr = CommandA.SetCommandText(SELECT_ALLFROMTBL),S_OK);
	TESTC_(hr = CommandA.Execute(&Aggregate, IID_IRow, &pIUnkInner), DB_E_NOAGGREGATION);

	//Create a row object from IOpenRowset asking for IID_IRow.
	//But we are setting the DBPROP_IRow property, so the results is a row object not a rowset...
	TEST2C_(hr = CommandA.SetProperties(), S_OK, DB_E_ERRORSOCCURRED);
	if(SUCCEEDED(hr))
	{
		TEST4C_(hr = CommandA.Execute(&Aggregate, IID_IUnknown, &pIUnkInner), S_OK, DB_S_NOTSINGLETON, DB_E_NOAGGREGATION, DB_E_ERRORSOCCURRED);
		Aggregate.SetUnkInner(pIUnkInner);
	}

	if(hr == DB_E_ERRORSOCCURRED)
	{
		//The only reason DB_E_ERRORSOCCURRED should be returned would be if the provider doesn't
		//support singleton row objects to be returned from OpenRowset or Execute.

		//NOTE: Sigleton objects are very useful, but none-the-less not required.
		//Verify the result with the advertised property value...
		TESTC(::GetProperty(DBPROP_OLEOBJECTS, DBPROPSET_DATASOURCEINFO, g_pIDBCreateSession, &dwValue));
		TESTC(!(dwValue & DBPROPVAL_OO_SINGLETON));
	}
	else
	{
		if(hr == DB_S_NOTSINGLETON)
			hr = S_OK;

		//Verify Aggregation for this row...
		TESTC_PROVIDER(Aggregate.VerifyAggregationQI(hr, IID_IRow));
	}

CLEANUP:
	SAFE_RELEASE(pIUnkInner);
	Aggregate.ReleaseInner();
	TRETURN
}
// }} TCW_VAR_PROTOTYPE_END

// {{ TCW_VAR_PROTOTYPE(48)
//*-----------------------------------------------------------------------
// @mfunc Aggregation - Session - > Row
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCIRow_GetColumns::Variation_48()
{
	TBEGIN
    CAggregate Aggregate;
	IUnknown* pIUnkInner = NULL;
	ULONG_PTR dwValue = 0;
	HRESULT hr = S_OK;

	COpenRowset OpenRowsetA;
	OpenRowsetA.SetProperty(DBPROP_IRow);

	//Try the invalid senario first... (asking for non-IUnknown)
	TESTC_(hr = OpenRowsetA.CreateOpenRowset(IID_IRow, &pIUnkInner, &Aggregate, ROW_INTERFACE), DB_E_NOAGGREGATION);

	//Create a row object from IOpenRowset asking for IID_IRow.
	//But we are setting the DBPROP_IRow property, so the results is a row object not a rowset...
	OpenRowsetA.SetProperty(DBPROP_IRow);
	TEST4C_(hr = OpenRowsetA.CreateOpenRowset(IID_IUnknown, &pIUnkInner, &Aggregate, ROW_INTERFACE), S_OK, DB_S_NOTSINGLETON, DB_E_NOAGGREGATION, DB_E_ERRORSOCCURRED);
	Aggregate.SetUnkInner(pIUnkInner);

	if(hr == DB_E_ERRORSOCCURRED)
	{
		//The only reason DB_E_ERRORSOCCURRED should be returned would be if the provider doesn't
		//support singleton row objects to be returned from OpenRowset or Execute.

		//NOTE: Sigleton objects are very useful, but none-the-less not required.
		//Verify the result with the advertised property value...
		TESTC(::GetProperty(DBPROP_OLEOBJECTS, DBPROPSET_DATASOURCEINFO, g_pIDBCreateSession, &dwValue));
		TESTC(!(dwValue & DBPROPVAL_OO_SINGLETON));
	}
	else
	{
		if(hr == DB_S_NOTSINGLETON)
			hr = S_OK;

		//Verify Aggregation for this row...
		TESTC_PROVIDER(Aggregate.VerifyAggregationQI(hr, IID_IRow));
	}

CLEANUP:
	SAFE_RELEASE(pIUnkInner);
	Aggregate.ReleaseInner();
	TRETURN
}
// }} TCW_VAR_PROTOTYPE_END

// {{ TCW_VAR_PROTOTYPE(49)
//*-----------------------------------------------------------------------
// @mfunc Aggregation - Rowset -> Row
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCIRow_GetColumns::Variation_49()
{
	TBEGIN
	HROW hRow = NULL;
    CAggregate Aggregate;
	IUnknown* pIUnkInner = NULL;
	CRowset RowsetA;
	HRESULT hr = S_OK;

	//Create a rowset
	TESTC_(RowsetA.CreateRowset(),S_OK)

	//Obtain the second row object (aggregated)
	hr = RowsetA.GetRowObject(&Aggregate, FIRST_ROW, IID_IUnknown, &pIUnkInner);
	Aggregate.SetUnkInner(pIUnkInner);

	//Verify Aggregation...
	TESTC_PROVIDER(Aggregate.VerifyAggregationQI(hr, IID_IRow));

CLEANUP:
	RowsetA.ReleaseRows(hRow);
	SAFE_RELEASE(pIUnkInner);
	Aggregate.ReleaseInner();
	TRETURN
}
// }} TCW_VAR_PROTOTYPE_END

// {{ TCW_VAR_PROTOTYPE(50)
//*-----------------------------------------------------------------------
// @mfunc Empty
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCIRow_GetColumns::Variation_50()
{
	return TEST_SKIPPED;
}
// }} TCW_VAR_PROTOTYPE_END

// {{ TCW_VAR_PROTOTYPE(51)
//*-----------------------------------------------------------------------
// @mfunc Empty
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCIRow_GetColumns::Variation_51()
{
	return TEST_SKIPPED;
}
// }} TCW_VAR_PROTOTYPE_END

// {{ TCW_VAR_PROTOTYPE(52)
//*-----------------------------------------------------------------------
// @mfunc Properties - DBPROP_IRow
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCIRow_GetColumns::Variation_52()
{
	TBEGIN
	IUnknown* pIUnknown = NULL;
	HRESULT hr = S_OK;
	ULONG i;
	//Make sure the required Row Object properties (including DBPROP_IRow) are supported
	for(i=0; i<cInterfaceIIDs; i++)
	{
		INTERFACEMAP* pMap = &rgInterfaceIIDs[i];
		if(pMap->dwPropertyID)
		{
			//Make sure this property is supported.
			if(SupportedProperty(pMap->dwPropertyID, DBPROPSET_ROWSET))
			{
				//See is this interface is available
				TEST2C_(hr = m_pCRowObject->pIRow()->QueryInterface(*pMap->pIID, (void**)&pIUnknown), S_OK, E_NOINTERFACE);
				if(SUCCEEDED(hr))
				{
					TESTC(DefaultObjectTesting(pIUnknown, ROW_INTERFACE));
					SAFE_RELEASE(pIUnknown);
				}
				else
				{
					//Make sure this is not one of the mandatory interfaces
					//All of the mandotry interfaces must be supported
					if(pMap->fMandatory)
						TERROR(L"Mandatory Property not supported " << pMap->pwszName);
				}
			}
			else
			{
				//Make sure this is not one of the mandatory properties.
				//All of the mandotry properties must be supported
				if(pMap->fMandatory)
					TERROR(L"Mandatory Property not supported " << pMap->pwszName);

				//Make sure this interface is not supported, since the property is not
				if(E_NOINTERFACE != m_pCRowObject->pIRow()->QueryInterface(*pMap->pIID, (void**)&pIUnknown))
					TERROR(L"Interface available although property failed for " << GetInterfaceName(*pMap->pIID));
			}
		}
	}

CLEANUP:
	SAFE_RELEASE(pIUnknown);
	TRETURN
}
// }} TCW_VAR_PROTOTYPE_END

// {{ TCW_VAR_PROTOTYPE(53)
//*-----------------------------------------------------------------------
// @mfunc Properties - DBPROP_OLEOBJECTS - DBPROPVAL_OO_ROWOBJECT
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCIRow_GetColumns::Variation_53()
{
	TBEGIN
	ULONG_PTR dwObjects = 0;

	CRowset RowsetA;
	CRowObject RowObjectA;
	TESTC_(RowsetA.CreateRowset(),S_OK);

	//If we have made it pass ModuleInit, then the provider supports Row Objects
	//So make sure they also advertise they support row objects through the property.
	//Required for early bound applications, vs. runtime applications
	TESTC(::GetProperty(DBPROP_OLEOBJECTS, DBPROPSET_DATASOURCEINFO, g_pIDBCreateSession, &dwObjects));
	TESTC(BITSET(dwObjects, DBPROPVAL_OO_ROWOBJECT) || BITSET(dwObjects, DBPROPVAL_OO_SINGLETON));

	//Make sure the property only contains valid flags
	TESTC(!(dwObjects & ~(DBPROPVAL_OO_BLOB |
						DBPROPVAL_OO_IPERSIST |
						DBPROPVAL_OO_DIRECTBIND |
						DBPROPVAL_OO_ROWOBJECT |
						DBPROPVAL_OO_SCOPED |
						DBPROPVAL_OO_SINGLETON)));

	//Now make sure the property was correctly represents whats supported...
	TESTC_(RowsetA.GetRowObject(FIRST_ROW, &RowObjectA, DBPROPVAL_OO_SINGLETON), dwObjects & DBPROPVAL_OO_SINGLETON ? S_OK : E_NOINTERFACE);
	TESTC_(RowsetA.GetRowObject(FIRST_ROW, &RowObjectA, DBPROPVAL_OO_ROWOBJECT), dwObjects & DBPROPVAL_OO_ROWOBJECT ? S_OK : E_NOINTERFACE);

CLEANUP:
	TRETURN
}
// }} TCW_VAR_PROTOTYPE_END

// {{ TCW_VAR_PROTOTYPE(54)
//*-----------------------------------------------------------------------
// @mfunc Properties - DBPROP_OLEOBJECTS - DBPROPVAL_OO_SINGLETON
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCIRow_GetColumns::Variation_54()
{
	TBEGIN
	CRowset RowsetA;
	IUnknown* pIUnknown = NULL;
	ULONG_PTR dwValue = 0;

	ULONG cPropSets = 0;
	DBPROPSET* rgPropSets = NULL;
	::SetProperty(DBPROP_IRow, DBPROPSET_ROWSET, &cPropSets, &rgPropSets);

	//NOTE: Sigleton objects are very useful, but none-the-less not required.
	//Verify the result with the advertised property value...
	if(::GetProperty(DBPROP_OLEOBJECTS, DBPROPSET_DATASOURCEINFO, g_pIDBCreateSession, &dwValue) &&
		dwValue & DBPROPVAL_OO_SINGLETON)
	{
		//Create a row object from ICommand::Execute asking for IID_IRow
		TEST2C_(RowsetA.pTable()->CreateRowset(SELECT_ALLFROMTBL, IID_IRow, 0, NULL, &pIUnknown), S_OK, DB_S_NOTSINGLETON);
		TESTC(DefaultObjectTesting(pIUnknown, ROW_INTERFACE));
		SAFE_RELEASE(pIUnknown);

		//Create a row object from IOpenRowset asking for IID_IRown.
		//But we are setting the DBPROP_IRow property, so the results is a row object not a rowset...
		TEST2C_(RowsetA.pTable()->CreateRowset(USE_OPENROWSET, IID_IRow, 0, NULL, &pIUnknown), S_OK, DB_S_NOTSINGLETON);
		TESTC(DefaultObjectTesting(pIUnknown, ROW_INTERFACE));
		SAFE_RELEASE(pIUnknown);

		//Create a row object from ICommand::Execute asking for IID_IUnknown.
		//But we are setting the DBPROP_IRow property, so the results is a row object not a rowset...
		TEST2C_(RowsetA.pTable()->CreateRowset(SELECT_ALLFROMTBL, IID_IUnknown, cPropSets, rgPropSets, &pIUnknown),S_OK,DB_S_NOTSINGLETON);
		TESTC(DefaultObjectTesting(pIUnknown, ROW_INTERFACE));
		SAFE_RELEASE(pIUnknown);

		//Create a row object from IOpenRowset asking for IID_IRown.
		//But we are setting the DBPROP_IRow property, so the results is a row object not a rowset...
		TEST2C_(RowsetA.pTable()->CreateRowset(USE_OPENROWSET, IID_IUnknown, cPropSets, rgPropSets, &pIUnknown), S_OK, DB_S_NOTSINGLETON);
		TESTC(DefaultObjectTesting(pIUnknown, ROW_INTERFACE));
		SAFE_RELEASE(pIUnknown);
	}
	else
	{
		TESTC_(RowsetA.pTable()->CreateRowset(SELECT_ALLFROMTBL, IID_IRow, 0, NULL, &pIUnknown),E_NOINTERFACE);
		TESTC_(RowsetA.pTable()->CreateRowset(USE_OPENROWSET, IID_IRow, 0, NULL, &pIUnknown),E_NOINTERFACE);
		TESTC_(RowsetA.pTable()->CreateRowset(SELECT_ALLFROMTBL, IID_IUnknown, cPropSets, rgPropSets, &pIUnknown),E_NOINTERFACE);
		TESTC_(RowsetA.pTable()->CreateRowset(USE_OPENROWSET, IID_IUnknown, cPropSets, rgPropSets, &pIUnknown),E_NOINTERFACE);
	}

CLEANUP:
	SAFE_RELEASE(pIUnknown);
	::FreeProperties(&cPropSets, &rgPropSets);
	TRETURN
}
// }} TCW_VAR_PROTOTYPE_END

// {{ TCW_VAR_PROTOTYPE(55)
//*-----------------------------------------------------------------------
// @mfunc Empty
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCIRow_GetColumns::Variation_55()
{
	return TEST_SKIPPED;
}
// }} TCW_VAR_PROTOTYPE_END

// {{ TCW_VAR_PROTOTYPE(56)
//*-----------------------------------------------------------------------
// @mfunc Properties - All Row Object Properties
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCIRow_GetColumns::Variation_56()
{
	TBEGIN
	CRowset RowsetA;
	IUnknown* pIUnknown = NULL;
	IUnknown* pIUnknown2 = NULL;

	ULONG cPropSets = 0;
	DBPROPSET* rgPropSets = NULL;
	HRESULT hr = S_OK;
	ULONG i;

	//Set all Row Object Properties (REQUIRED)
	for(i=0; i<cInterfaceIIDs; i++)
	{
		INTERFACEMAP* pMap = &rgInterfaceIIDs[i];
		if(pMap->dwPropertyID)
			::SetProperty(pMap->dwPropertyID, 	DBPROPSET_ROWSET, &cPropSets, &rgPropSets);
	}

	//OpenRowset
	TEST3C_(hr = RowsetA.pTable()->CreateRowset(USE_OPENROWSET, IID_IUnknown, cPropSets, rgPropSets, &pIUnknown),S_OK,DB_S_NOTSINGLETON,DB_E_ERRORSOCCURRED);

	//Verify a Row object is returned...
	if(pIUnknown)
		TESTC(DefaultObjectTesting(pIUnknown, ROW_INTERFACE));

	//Verify returned Properties...
	for(i=0; i<cInterfaceIIDs; i++)
	{
		INTERFACEMAP* pMap = &rgInterfaceIIDs[i];
		if(pMap->dwPropertyID)
		{
			DBPROP* pProp = NULL;
			TESTC(FindProperty(pMap->dwPropertyID, DBPROPSET_ROWSET, cPropSets, rgPropSets, &pProp));

			//If the property succeeded, then the interface must be available.
			//(ie: provider can always return extra functionalty, but must at least the mininal asked for)
			if(pProp->dwStatus == DBPROPSTATUS_OK)
			{
				if(SUCCEEDED(hr))
				{
					//Then all the properties must have succeeded
					TESTC(VerifyPropSetStatus(cPropSets, rgPropSets, DBPROPSTATUS_OK));

					//Make sure the interface is available
					if(S_OK != pIUnknown->QueryInterface(*pMap->pIID, (void**)&pIUnknown2))
						TERROR(L"Interface not available although property succeeded for " << GetInterfaceName(*pMap->pIID));
					TESTC(DefaultObjectTesting(pIUnknown2, ROW_INTERFACE));
					SAFE_RELEASE(pIUnknown2);
				}
			}
			else
			{
				//Some providers still don't met the spec and fail DBPROP_I*,
				//since the property DBPROP_I* was set and the interface IID_I* was not asked
				//for.  This is wrong, and against the spec, which states that asking for
				//DBPROP_I* is just like implicilty asking for IID_I*.  Test it here,
				//to make sure the provider truely doesn't support this interface,
				//so we don't skip them incorrectly

				//The mandatory properties cannot fail...
				if(pMap->fMandatory)
					TERROR(L"Mandatory Property failed for " << pMap->pwszName << "\n");

				//Optional properties can be not supported.
				//NOTE: Some optional row object properties may not be supported on the row object
				//even though they are supported on the rowset.  (ie: IConnectionPointContainer).
				TESTC(pProp->dwStatus == DBPROPSTATUS_NOTSUPPORTED ||
					pProp->dwStatus == DBPROPSTATUS_CONFLICTING);

				//Make sure the interface is not available
				if(SUCCEEDED(hr))
				{
					TESTC_(pIUnknown->QueryInterface(*pMap->pIID, (void**)&pIUnknown2), E_NOINTERFACE);
				}

				//Make sure asking for the IID also fails...
				//NOTE: We have to set the DBPROP_IRow for some cases...
				ULONG cRowProp = 0;
				DBPROPSET* rgRowProp = NULL;
				if(!(*pMap->pIID == IID_IRow || *pMap->pIID == IID_IRowChange || *pMap->pIID == IID_IRowSchemaChange))
					::SetProperty(DBPROP_IRow, DBPROPSET_ROWSET, &cRowProp, &rgRowProp);

				if(RowsetA.pTable()->CreateRowset(USE_OPENROWSET, *pMap->pIID, cRowProp, rgRowProp, &pIUnknown)!=E_NOINTERFACE)
					TERROR(L"Property Incorrect for " << GetPropertyName(pMap->dwPropertyID, DBPROPSET_ROWSET) << "\n");
				::FreeProperties(&cRowProp, &rgRowProp);
			}
		}
	}

CLEANUP:
	SAFE_RELEASE(pIUnknown);
	SAFE_RELEASE(pIUnknown2);
	::FreeProperties(&cPropSets, &rgPropSets);
	TRETURN
}
// }} TCW_VAR_PROTOTYPE_END

// {{ TCW_VAR_PROTOTYPE(57)
//*-----------------------------------------------------------------------
// @mfunc Properties - All Row Object Properties Optional
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCIRow_GetColumns::Variation_57()
{
	TBEGIN
	CRowset RowsetA;
	IUnknown* pIUnknown = NULL;
	IUnknown* pIUnknown2 = NULL;
	HRESULT hr = S_OK;

	ULONG cPropSets = 0;
	DBPROPSET* rgPropSets = NULL;
	ULONG i;

	//Set all Row Object Properties (Mandatory-REQUIRED, Optional-OPTIONAL)
	for(i=0; i<cInterfaceIIDs; i++)
	{
		INTERFACEMAP* pMap = &rgInterfaceIIDs[i];
		if(pMap->dwPropertyID)
			::SetProperty(pMap->dwPropertyID, 	DBPROPSET_ROWSET, &cPropSets, &rgPropSets, (void*)VARIANT_TRUE, DBTYPE_BOOL, pMap->fMandatory ? DBPROPOPTIONS_REQUIRED : DBPROPOPTIONS_OPTIONAL);
	}

	//OpenRowset
	TEST3C_(hr = RowsetA.pTable()->CreateRowset(USE_OPENROWSET, IID_IUnknown, cPropSets, rgPropSets, &pIUnknown),S_OK,DB_S_NOTSINGLETON,DB_S_ERRORSOCCURRED);

	//Verify a Row object is returned...
	TESTC(DefaultObjectTesting(pIUnknown, ROW_INTERFACE));

	//Verify returned Properties...
	for(i=0; i<cInterfaceIIDs; i++)
	{
		INTERFACEMAP* pMap = &rgInterfaceIIDs[i];
		if(pMap->dwPropertyID)
			TCOMPARE_(VerifyPropStatus(cPropSets, rgPropSets, pMap->dwPropertyID, DBPROPSET_ROWSET, DBPROPSTATUS_OK));
	}

	//NOTE: The spec indicates that DB_S_ERRORSOCCURRED, superceeds DB_S_NOTSINGLETON.
	//So if there are any property errors then DB_S_ERRORSOCCURRED is returned.  DB_S_NOTSINGLETON
	//will only be returned in the case that no property errors...
	if(hr == DB_S_NOTSINGLETON)
	{
		//Then all the properties must have succeeded
		TESTC(VerifyPropSetStatus(cPropSets, rgPropSets, DBPROPSTATUS_OK));
	}

	//For all properties that did succeed, the interface should be available...
	for(i=0; i<cInterfaceIIDs; i++)
	{
		INTERFACEMAP* pMap = &rgInterfaceIIDs[i];
		if(pMap->dwPropertyID)
		{
			DBPROP* pProp = NULL;
			TESTC(FindProperty(pMap->dwPropertyID, DBPROPSET_ROWSET, cPropSets, rgPropSets, &pProp));

			//If the property succeeded, then the interface must be available.
			//(ie: provider can always return extra functionalty, but must at least the mininal asked for)
			if(pProp->dwStatus == DBPROPSTATUS_OK)
			{
				if(SUCCEEDED(hr))
				{
					if(S_OK != pIUnknown->QueryInterface(*pMap->pIID, (void**)&pIUnknown2))
						TERROR(L"Interface not available although property succeeded for " << GetInterfaceName(*pMap->pIID));

					TESTC(DefaultObjectTesting(pIUnknown2, ROW_INTERFACE));
					SAFE_RELEASE(pIUnknown2);
				}
			}
			else
			{
				//Some providers still don't met the spec and fail DBPROP_I*,
				//since the property DBPROP_I* was set and the interface IID_I* was not asked
				//for.  This is wrong, and against the spec, which states that asking for
				//DBPROP_I* is just like implicilty asking for IID_I*.  Test it here,
				//to make sure the provider truely doesn't support this interface,
				//so we don't skip them incorrectly

				//The mandatory properties cannot fail...
				TESTC(!pMap->fMandatory);

				if(SUCCEEDED(hr))
				{
					//Make sure the interface is not available
					TESTC_(pIUnknown->QueryInterface(*pMap->pIID, (void**)&pIUnknown2), E_NOINTERFACE);
				}

				//Make sure asking for the IID also fails...
				//NOTE: We have to set the DBPROP_IRow for some cases...
				ULONG cRowProp = 0;
				DBPROPSET* rgRowProp = NULL;
				if(!(*pMap->pIID == IID_IRow || *pMap->pIID == IID_IRowChange || *pMap->pIID == IID_IRowSchemaChange))
					::SetProperty(DBPROP_IRow, DBPROPSET_ROWSET, &cRowProp, &rgRowProp);

				if(RowsetA.pTable()->CreateRowset(USE_OPENROWSET, *pMap->pIID, cRowProp, rgRowProp, &pIUnknown2)!=E_NOINTERFACE)
					TERROR(L"Property Incorrect for " << GetPropertyName(pMap->dwPropertyID, DBPROPSET_ROWSET) << "\n");
				::FreeProperties(&cRowProp, &rgRowProp);
			}
		}
	}

CLEANUP:
	SAFE_RELEASE(pIUnknown);
	SAFE_RELEASE(pIUnknown2);
	::FreeProperties(&cPropSets, &rgPropSets);
	TRETURN
}
// }} TCW_VAR_PROTOTYPE_END

// {{ TCW_VAR_PROTOTYPE(58)
//*-----------------------------------------------------------------------
// @mfunc Empty
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCIRow_GetColumns::Variation_58()
{
	return TEST_SKIPPED;
}
// }} TCW_VAR_PROTOTYPE_END

// {{ TCW_VAR_PROTOTYPE(59)
//*-----------------------------------------------------------------------
// @mfunc Properties - Rowset Properties
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCIRow_GetColumns::Variation_59()
{
	TBEGIN
	CRowset RowsetA;
	CRowObject RowObjectA;
	ULONG_PTR dwValue = 0;
	ULONG cPropSets = 0;
	DBPROPSET* rgPropSets = NULL;
	IRow* pIRow = NULL;

	//This variation require Singleton row objects.  To test different properties on the row object.
	TESTC_PROVIDER(::GetProperty(DBPROP_OLEOBJECTS, DBPROPSET_DATASOURCEINFO, g_pIDBCreateSession, &dwValue) &&
		dwValue & DBPROPVAL_OO_SINGLETON);

	//Set some interesting Rowset properties, to make sure their ignored (or correctly looked at) on the row object...
	//TODO: We need to improve GetRowObject to set more than just AccessOrder, so all our rowset
	//proopery scenarios are already covered.  For now just do a good combination of rowset properties.
	::SetSettableProperty(DBPROP_ACCESSORDER,		DBPROPSET_ROWSET, &cPropSets, &rgPropSets, (void*)DBPROPVAL_AO_RANDOM, DBTYPE_I4);
//	::SetSettableProperty(DBPROP_OTHERUPDATEDELETE, DBPROPSET_ROWSET, &cPropSets, &rgPropSets);
//	::SetSettableProperty(DBPROP_UNIQUEROWS,		DBPROPSET_ROWSET, &cPropSets, &rgPropSets);

	//Create a row object from ICommand::Execute asking for IID_IRow
	TEST2C_(RowsetA.pTable()->CreateRowset(SELECT_ORDERBYNUMERIC, IID_IRow, cPropSets, rgPropSets, (IUnknown**)&pIRow), S_OK, DB_S_NOTSINGLETON);
	RowObjectA.SetRowObject(pIRow);

	//Verify the Row object returned...
	TESTC(RowObjectA.VerifyGetColumns(FIRST_ROW, RowsetA.pTable(), ALL_COLS_BOUND));
	TESTC(RowObjectA.VerifyGetColumns(FIRST_ROW, RowsetA.pTable(), ALL_COLS_BOUND));

CLEANUP:
	SAFE_RELEASE(pIRow);
	::FreeProperties(&cPropSets, &rgPropSets);
	TRETURN
}
// }} TCW_VAR_PROTOTYPE_END

// {{ TCW_VAR_PROTOTYPE(60)
//*-----------------------------------------------------------------------
// @mfunc Empty
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCIRow_GetColumns::Variation_60()
{
	// TO DO:  Add your own code here
	return TRUE;
}
// }} TCW_VAR_PROTOTYPE_END

// {{ TCW_VAR_PROTOTYPE(61)
//*-----------------------------------------------------------------------
// @mfunc Threads - GetColumns seperate threads
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCIRow_GetColumns::Variation_61()
{
	TBEGIN
	INIT_THREADS(MAX_THREADS);

	//Setup Thread Arguments
	THREADARG T1Arg = { this, m_pCRowObject };

	//Create Threads
	CREATE_THREADS(Thread_VerifyGetColumns, &T1Arg);

	START_THREADS();
	END_THREADS();

	TRETURN
}
// }} TCW_VAR_PROTOTYPE_END

// {{ TCW_VAR_PROTOTYPE(62)
//*-----------------------------------------------------------------------
// @mfunc Empty
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCIRow_GetColumns::Variation_62()
{
	return TEST_SKIPPED;
}
// }} TCW_VAR_PROTOTYPE_END

// {{ TCW_VAR_PROTOTYPE(63)
//*-----------------------------------------------------------------------
// @mfunc Boundary - DB_E_DELETEDROW
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCIRow_GetColumns::Variation_63()
{
	TBEGIN
	DBCOUNTITEM cRowsObtained = 0;
	HROW* rghRows = NULL;
	HROW hLastRow = NULL;

	CRowsetChange RowsetA;
	CRowObject RowObjectA;
	HRESULT hr = S_OK;

	//Create a new rowset
	//Provider must support IRowsetChange
	TESTC_PROVIDER(RowsetA.CreateRowset()==S_OK);

	//Obtain the last row handle
	//We could just do (-1, 1) or (0, -1) but that would require fetching backwards...
	TEST3C_(hr = RowsetA.GetNextRows(0, 1000, &cRowsObtained, &rghRows), S_OK, DB_S_ENDOFROWSET, DB_S_ROWLIMITEXCEEDED);
	TESTC(cRowsObtained && rghRows);
	hLastRow = rghRows[cRowsObtained - 1];

	//Now create the row object.
	TEST3C_(hr=RowObjectA.CreateRowObject(RowsetA.pIRowset(), hLastRow), S_OK, DB_S_NOROWSPECIFICCOLUMNS,E_NOINTERFACE);
	if(hr == E_NOINTERFACE)
	{
		odtLog << "This provider does not support IGetRow interface\n";
		TESTB = TEST_SKIPPED;
		goto CLEANUP;
	}

	//While the row object is open, delete the row out from under it...
	//NOTE: The other senario, deleting the row handle before creating
	//the row object is done in the IGetRow test
	TESTC_(RowsetA.DeleteRow(hLastRow),S_OK);
	RowsetA.pTable()->SubtractRow();

	//Now try and use the row object
	TESTC_(RowObjectA.GetColumns(RowObjectA.m_cColAccess, RowObjectA.m_rgColAccess), DB_E_DELETEDROW);

CLEANUP:
	RowsetA.ReleaseRows(cRowsObtained, rghRows);
	PROVIDER_FREE(rghRows);
	TRETURN
}
// }} TCW_VAR_PROTOTYPE_END

// {{ TCW_VAR_PROTOTYPE(64)
//*-----------------------------------------------------------------------
// @mfunc Boundary - DB_E_DELETEDROW - Bufferred Mode
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCIRow_GetColumns::Variation_64()
{
	TBEGIN
	HROW hRow = NULL;
	CRowsetUpdate RowsetA;
	CRowObject RowObjectA;
	HRESULT hr = E_FAIL;

	//Create a new rowset
	//Provider must support IRowsetUpdate
	TESTC_PROVIDER(RowsetA.CreateRowset()==S_OK);

	//Obtain the first row handle
	TESTC_(RowsetA.GetNextRows(&hRow),S_OK);

	//Now create the row object.
	TEST3C_(hr = RowObjectA.CreateRowObject(RowsetA.pIRowset(), hRow), S_OK, DB_S_NOROWSPECIFICCOLUMNS,E_NOINTERFACE);
	if(hr == E_NOINTERFACE)
	{
		odtLog << "This provider does not support IGetRow interface\n";
		TESTB = TEST_SKIPPED;
		goto CLEANUP;
	}

	//While the row object is open, delete the row out from under it...
	//NOTE: The other senario, deleting the row handle before creating
	//the row object is done in the IGetRow test
	TESTC_(RowsetA.DeleteRow(hRow),S_OK);

	//Now try and use the row object
	TESTC_(RowObjectA.GetColumns(RowObjectA.m_cColAccess, RowObjectA.m_rgColAccess), DB_E_DELETEDROW);

	//Actually Update the backend
	TESTC_(RowsetA.UpdateRow(hRow),S_OK);
	RowsetA.pTable()->SubtractRow();
	TESTC_(RowObjectA.GetColumns(RowObjectA.m_cColAccess, RowObjectA.m_rgColAccess), DB_E_DELETEDROW);

CLEANUP:
	RowsetA.ReleaseRows(hRow);
	TRETURN
}
// }} TCW_VAR_PROTOTYPE_END

// {{ TCW_TERMINATE_METHOD
//*-----------------------------------------------------------------------
// @mfunc TestCase Termination Routine
//
// @rdesc TEST_PASS or TEST_FAIL
//
BOOL TCIRow_GetColumns::Terminate()
{
// {{ TCW_TERM_BASECLASS_CHECK2
	return(TCIRow::Terminate());
} 	// }}
// }} TCW_TERMINATE_METHOD_END
// }} TCW_TC_PROTOTYPE_END

// {{ TCW_TC_PROTOTYPE(TCIRow_GetSourceRowset)
//*-----------------------------------------------------------------------
//| Test Case:		TCIRow_GetSourceRowset - IRow::GetSourceRowset
//| Created:  	8/5/98
//*-----------------------------------------------------------------------

//*-----------------------------------------------------------------------
// @mfunc TestCase Initialization Routine
//
// @rdesc TRUE or FALSE
//
BOOL TCIRow_GetSourceRowset::Init()
{
	// {{ TCW_INIT_BASECLASS_CHECK
	if(TCIRow::Init())
	// }}
	{
		return TRUE;
	}
	return FALSE;
}

// {{ TCW_VAR_PROTOTYPE(1)
//*-----------------------------------------------------------------------
// @mfunc riid - All Mandatory interfaces
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCIRow_GetSourceRowset::Variation_1()
{
	TBEGIN
	HRESULT hr = S_OK;
	IUnknown* pIUnknown = NULL;
	ULONG i;
	//Obtain the Rowset interfaces...
	ULONG cRowsetIIDs = 0;
	INTERFACEMAP* rgRowsetIIDs = NULL;
	GetInterfaceArray(ROWSET_INTERFACE, &cRowsetIIDs, &rgRowsetIIDs);

	//For every [MANDATORY] interface, try to object the parent rowset object...
	for(i=0; i<cRowsetIIDs; i++)
	{
		//IRow::GetSourceRowset
		hr = m_pCRowObject->GetSourceRowset(*rgRowsetIIDs[i].pIID, (IUnknown**)&pIUnknown, NULL);
		if(hr==DB_E_NOSOURCEOBJECT)
			TWARNING(L"Unable to obtain parent object?");

		//Determine results
		if(rgRowsetIIDs[i].fMandatory)
		{
			//[MANDATORY]
			if(hr!=S_OK && hr!=DB_E_NOSOURCEOBJECT)
			{
				CHECK(hr, S_OK);
				TOUTPUT_(L"ERROR: Interface Incorrect for " << GetInterfaceName(*rgRowsetIIDs[i].pIID) << "\n");
			}
		}
		else
		{
			//[OPTIONAL]
			if(hr!=S_OK && hr!=DB_E_NOSOURCEOBJECT && hr!=E_NOINTERFACE)
			{
				CHECK(hr, S_OK);
				TOUTPUT_(L"ERROR: Interface Incorrect for " << GetInterfaceName(*rgRowsetIIDs[i].pIID) << "\n");
			}
		}
		SAFE_RELEASE(pIUnknown);
	}

	SAFE_RELEASE(pIUnknown);
	TRETURN
}
// }} TCW_VAR_PROTOTYPE_END

// {{ TCW_VAR_PROTOTYPE(2)
//*-----------------------------------------------------------------------
// @mfunc Empty
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCIRow_GetSourceRowset::Variation_2()
{
	return TEST_SKIPPED;
}
// }} TCW_VAR_PROTOTYPE_END

// {{ TCW_VAR_PROTOTYPE(3)
//*-----------------------------------------------------------------------
// @mfunc Optional Args - [any riid, NULL, NULL] - S_OK
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCIRow_GetSourceRowset::Variation_3()
{
	TBEGIN

	//Get the Original Reference count...
	ULONG ulOrgRefCount = GetRefCount(pIRowset());

	//IRow::GetSourceRowset
	//NOTE: The spec doesn't inforce order of error processing.  So if a provider is able to determine
	//they don't have a source object, (before) determining there are no output params, we have
	//to allow for both errors.
	TEST2C_(m_pCRowObject->GetSourceRowset(IID_IUnknown, NULL, NULL), E_INVALIDARG, DB_E_NOSOURCEOBJECT);

	//Make sure the refcount was not incresed since we don't have a pointer to release...
	TESTC(ulOrgRefCount == GetRefCount(pIRowset()));

CLEANUP:
	TRETURN
}
// }} TCW_VAR_PROTOTYPE_END

// {{ TCW_VAR_PROTOTYPE(4)
//*-----------------------------------------------------------------------
// @mfunc Optional Args - [any riid, NULL, valid] - S_OK with hRow
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCIRow_GetSourceRowset::Variation_4()
{
	TBEGIN
	HROW hRow = NULL;
	HRESULT hr = S_OK;

	//IRow::GetSourceRowset
	TEST2C_(hr = m_pCRowObject->GetSourceRowset(IID_IUnknown, NULL, &hRow),S_OK,DB_E_NOSOURCEOBJECT);

	//Verify this row handle...
	if(SUCCEEDED(hr))
	{
		TESTC(VerifyRowHandles(hRow, FIRST_ROW));
	}

CLEANUP:
	ReleaseRows(hRow);
	TRETURN
}
// }} TCW_VAR_PROTOTYPE_END

// {{ TCW_VAR_PROTOTYPE(5)
//*-----------------------------------------------------------------------
// @mfunc Optional Args - [IID_IUnknown, valid, NULL] - S_OK with Rowset
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCIRow_GetSourceRowset::Variation_5()
{
	TBEGIN
	IUnknown* pIUnknown = NULL;
	HRESULT hr = S_OK;

	//IRow::GetSourceRowset
	TEST2C_(hr = m_pCRowObject->GetSourceRowset(IID_IUnknown, &pIUnknown, NULL),S_OK,DB_E_NOSOURCEOBJECT);

	//Verify the rowset returned...
	if(SUCCEEDED(hr))
	{
		//NOTE: This is already done in the GetSourceRowset helper, but just for completeness...
		TESTC(DefaultObjectTesting(pIUnknown, ROWSET_INTERFACE));
	}

CLEANUP:
	SAFE_RELEASE(pIUnknown);
	TRETURN
}
// }} TCW_VAR_PROTOTYPE_END

// {{ TCW_VAR_PROTOTYPE(6)
//*-----------------------------------------------------------------------
// @mfunc Optional Args - [IID_IRowset, valid, valid] - S_OK with Rowset and hRow
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCIRow_GetSourceRowset::Variation_6()
{
	TBEGIN
	IUnknown* pIUnknown = NULL;
	HROW hRow = NULL;
	HRESULT hr = S_OK;

	//IRow::GetSourceRowset
	TEST2C_(hr = m_pCRowObject->GetSourceRowset(IID_IUnknown, &pIUnknown, &hRow),S_OK,DB_E_NOSOURCEOBJECT);

	if(SUCCEEDED(hr))
	{
		//Verify the rowset returned...
		TESTC(DefaultObjectTesting(pIUnknown, ROWSET_INTERFACE));

		//Verify this row handle...
		TESTC(VerifyRowHandles(hRow, FIRST_ROW));
	}

CLEANUP:
	ReleaseRows(hRow);
	SAFE_RELEASE(pIUnknown);
	TRETURN
}
// }} TCW_VAR_PROTOTYPE_END

// {{ TCW_VAR_PROTOTYPE(7)
//*-----------------------------------------------------------------------
// @mfunc Empty
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCIRow_GetSourceRowset::Variation_7()
{
	return TEST_SKIPPED;
}
// }} TCW_VAR_PROTOTYPE_END

// {{ TCW_VAR_PROTOTYPE(8)
//*-----------------------------------------------------------------------
// @mfunc Sequence - Execute -> Row -> GetSourceRowset
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCIRow_GetSourceRowset::Variation_8()
{
	TBEGIN
	CRowset RowsetA;
	CRowObject RowObjectA;
	IRow* pIRow = NULL;
	IUnknown* pIUnknown = NULL;

	//Create a row object from ICommand::Execute
	TEST2C_(RowsetA.pTable()->CreateRowset(SELECT_ORDERBYNUMERIC, IID_IRow, 0, NULL, (IUnknown**)&pIRow),S_OK,DB_S_NOTSINGLETON);

	//Verify the Row object returned...
	TESTC_(RowObjectA.SetRowObject(pIRow),S_OK);
	TESTC(RowObjectA.VerifyGetColumns(FIRST_ROW, RowsetA.pTable(), ALL_COLS_BOUND));

	//Try to get back top the creating rowset object...
	TEST2C_(RowObjectA.GetSourceRowset(IID_IUnknown, &pIUnknown, NULL), S_OK, DB_E_NOSOURCEOBJECT);

CLEANUP:
	SAFE_RELEASE(pIRow);
	SAFE_RELEASE(pIUnknown);
	TRETURN
}
// }} TCW_VAR_PROTOTYPE_END

// {{ TCW_VAR_PROTOTYPE(9)
//*-----------------------------------------------------------------------
// @mfunc Sequence - Execute -> Rowset -> Row -> GetSourceRowset
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCIRow_GetSourceRowset::Variation_9()
{
	TBEGIN
	CRowset RowsetA;
	CRowObject RowObjectA;
	IUnknown* pIUnknown = NULL;
	HROW hRow = NULL;
	HRESULT hr = S_OK;

	//Create a rowset from ICommand::Execute
	TESTC_PROVIDER(m_ulpOleObjects & DBPROPVAL_OO_ROWOBJECT);
	TESTC_(RowsetA.CreateRowset(SELECT_ORDERBYNUMERIC),S_OK);

	//Create the Row Object from the rowset...
	TESTC_(RowsetA.GetNextRows(&hRow),S_OK);
	TEST2C_(RowObjectA.CreateRowObject(RowsetA.pIRowset(), hRow), S_OK, DB_S_NOROWSPECIFICCOLUMNS);
	TESTC(RowObjectA.VerifyGetColumns(FIRST_ROW, RowsetA.pTable(), ALL_COLS_BOUND));

	//Try to get back top the creating rowset object...
	TEST2C_(hr = RowObjectA.GetSourceRowset(IID_IUnknown, &pIUnknown, NULL), S_OK, DB_E_NOSOURCEOBJECT);
	if(SUCCEEDED(hr))
	{
		VerifyEqualInterface(pIUnknown, RowsetA.pIRowset());
	}

CLEANUP:
	SAFE_RELEASE(pIUnknown);
	RowsetA.ReleaseRows(hRow);
	TRETURN
}
// }} TCW_VAR_PROTOTYPE_END

// {{ TCW_VAR_PROTOTYPE(10)
//*-----------------------------------------------------------------------
// @mfunc Sequence - OpenRowset -> Row -> Release Rowset -> GetSourceRowset
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCIRow_GetSourceRowset::Variation_10()
{
	TBEGIN
	CRowset RowsetA;
	CRowObject RowObjectA;
	IRow* pIRow = NULL;
	IUnknown* pIUnknown = NULL;

	//Create a row object from IOpenRowset
	TEST2C_(RowsetA.pTable()->CreateRowset(USE_OPENROWSET, IID_IRow, 0, NULL, (IUnknown**)&pIRow),S_OK,DB_S_NOTSINGLETON);

	//Verify the Row object returned...
	TESTC_(RowObjectA.SetRowObject(pIRow),S_OK);
	TESTC(RowObjectA.VerifyGetColumns(FIRST_ROW, RowsetA.pTable(), ALL_COLS_BOUND));

	//Try to get back top the creating rowset object...
	TEST2C_(RowObjectA.GetSourceRowset(IID_IUnknown, &pIUnknown, NULL), S_OK, DB_E_NOSOURCEOBJECT);

CLEANUP:
	SAFE_RELEASE(pIRow);
	SAFE_RELEASE(pIUnknown);
	TRETURN
}
// }} TCW_VAR_PROTOTYPE_END

// {{ TCW_VAR_PROTOTYPE(11)
//*-----------------------------------------------------------------------
// @mfunc Sequence - OpenRowset -> Rowset -> Row -> Release Rowset -> GetSourceRowset
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCIRow_GetSourceRowset::Variation_11()
{
	TBEGIN
	CRowset RowsetA;
	CRowObject RowObjectA;
	IUnknown* pIUnknown = NULL;
	HROW hRow = NULL;
	HRESULT hr = S_OK;

	//Create a rowset from IOpenRowset
	TESTC_PROVIDER(m_ulpOleObjects & DBPROPVAL_OO_ROWOBJECT);
	TESTC_(RowsetA.CreateRowset(USE_OPENROWSET),S_OK);

	//Create the Row Object from the rowset...
	TESTC_(RowsetA.GetNextRows(2, ONE_ROW, &hRow),S_OK);
	TEST2C_(RowObjectA.CreateRowObject(RowsetA.pIRowset(), hRow), S_OK, DB_S_NOROWSPECIFICCOLUMNS);
	TESTC(RowObjectA.VerifyGetColumns(THIRD_ROW, RowsetA.pTable(), ALL_COLS_BOUND));

	//Release the Rowset.
	TESTC_(RowsetA.ReleaseRows(hRow),S_OK);
	RowsetA.DropRowset();

	//Try to get back top the creating rowset object...
	TEST2C_(RowObjectA.GetSourceRowset(IID_IUnknown, &pIUnknown, &hRow), S_OK, DB_E_NOSOURCEOBJECT);

	//Verify the row handle returned...
	TESTC_(RowsetA.CreateRowset(pIUnknown),S_OK);
	TESTC(RowsetA.VerifyRowHandles(ONE_ROW, &hRow, THIRD_ROW));
	TESTC_(RowsetA.ReleaseRows(hRow),S_OK);

	//The Rowset returned from GetSourceRowset, usally jsut returns the Rowset with a NFP
	//in the same place.  But since the user has completley released their refcounts, the rowset
	//may or may not still be alive by the providers implementation.  If they internally keep a reference
	//on it for the row, then the NFP will basically be where we left off, if not then it will
	//be at the start of the rowset.
	RowObjectA.ReleaseRowObject();
	TESTC_(RowsetA.GetNextRows(&hRow),S_OK);
	TESTC(RowsetA.VerifyRowHandles(ONE_ROW, &hRow, FOURTH_ROW) || RowsetA.VerifyRowHandles(ONE_ROW, &hRow, FIRST_ROW));

CLEANUP:
	SAFE_RELEASE(pIUnknown);
	RowsetA.ReleaseRows(hRow);
	TRETURN
}
// }} TCW_VAR_PROTOTYPE_END

// {{ TCW_VAR_PROTOTYPE(12)
//*-----------------------------------------------------------------------
// @mfunc Empty
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCIRow_GetSourceRowset::Variation_12()
{
	return TEST_SKIPPED;
}
// }} TCW_VAR_PROTOTYPE_END

// {{ TCW_VAR_PROTOTYPE(13)
//*-----------------------------------------------------------------------
// @mfunc Multiple - GetSourceRowset from numerous child row objects
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCIRow_GetSourceRowset::Variation_13()
{
	TBEGIN
	CRowset RowsetA;
	IUnknown* pIUnknown = NULL;
	HRESULT hr = S_OK;
	CRowObject** rgpCRowObjects = NULL;
	DBCOUNTITEM iRow, cRowsObtained = 0;
	HROW* rghRows = NULL;

	//Create a rowset from IOpenRowset
	TESTC_PROVIDER(m_ulpOleObjects & DBPROPVAL_OO_ROWOBJECT);
	TESTC_(RowsetA.CreateRowset(DBPROP_CANHOLDROWS),S_OK);

	//Grab as many rows as possible...
	TEST3C_(RowsetA.GetNextRows(0, 1000, &cRowsObtained, &rghRows), S_OK, DB_S_ENDOFROWSET, DB_S_ROWLIMITEXCEEDED);

	//Create the Row Objects from the rowset, (leave active)
	SAFE_ALLOC(rgpCRowObjects, CRowObject*, cRowsObtained);
	memset(rgpCRowObjects, 0, (size_t)(cRowsObtained * sizeof(CRowObject*)));

	//Loop over all the rows Obtained
	for(iRow=0; iRow<cRowsObtained; iRow++)
	{
		//Create the Row object
		CRowObject* pCRowObject = new CRowObject;
		rgpCRowObjects[iRow] = pCRowObject;
		TEST2C_(RowsetA.GetRowObject(iRow+1, pCRowObject, 0, rghRows[iRow]), S_OK, DB_S_NOROWSPECIFICCOLUMNS);

		//Try to get back to the creating rowset
		TEST2C_(pCRowObject->GetSourceRowset(IID_IUnknown, &pIUnknown, NULL), S_OK, DB_E_NOSOURCEOBJECT);
		if(pIUnknown)
		{
			//Make sure its returning the original object
			TESTC(VerifyEqualInterface(pIUnknown, RowsetA.pIRowset()));
		}
		SAFE_RELEASE(pIUnknown);
	}

CLEANUP:
	for(iRow=0; iRow<cRowsObtained && rgpCRowObjects; iRow++)
		SAFE_DELETE(rgpCRowObjects[iRow]);
	SAFE_FREE(rgpCRowObjects);
	SAFE_RELEASE(pIUnknown);
	RowsetA.ReleaseRows(cRowsObtained, rghRows);
	PROVIDER_FREE(rghRows);
	TRETURN
}
// }} TCW_VAR_PROTOTYPE_END

// {{ TCW_VAR_PROTOTYPE(14)
//*-----------------------------------------------------------------------
// @mfunc Multiple - Numerous Rowsets open, verify correct parent
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCIRow_GetSourceRowset::Variation_14()
{
	TBEGIN
	const ULONG cRowsets = 4;	//1 less than the number of rows in the table...
	CRowset Rowsets[cRowsets];
	CRowObject RowObjects[cRowsets];

	HROW rghRows[cRowsets];
	HROW hRow = NULL;
	IUnknown* pIRowset = NULL;
	HRESULT hr = S_OK;
	ULONG i;
	//Create rowset(s) from IOpenRowset
	for(i=0; i<cRowsets; i++)
	{
		//Create Rowsets
		TESTC_(Rowsets[i].CreateRowset(DBPROP_IRowsetIdentity),S_OK);

		//Grab different rows...
		//We use the loop counter as the offset into the rowset of which row to retrive...
		TESTC_(Rowsets[i].GetNextRows(i, 1, &rghRows[i]), S_OK);

		//Create Row Objects...
		TEST2C_(Rowsets[i].GetRowObject(i+1, &RowObjects[i], 0, rghRows[i]), S_OK, DB_S_NOROWSPECIFICCOLUMNS);
	}

	//Now try and Obtain the Source Rowsets...
	for(i=0; i<cRowsets; i++)
	{
		//Try to get back to the creating rowset
		TEST2C_(hr = RowObjects[i].GetSourceRowset(IID_IRowset, &pIRowset, &hRow), S_OK, DB_E_NOSOURCEOBJECT);
		if(SUCCEEDED(hr))
		{
			//Make sure its returning the original object
			TESTC(VerifyEqualInterface(pIRowset, Rowsets[i].pIRowset()));

			//Make sure the row returned is correct...
			TESTC(Rowsets[i].IsSameRow(rghRows[i], hRow));

			//Make sure the original next fetch position is unchanged...
			//GetSourceRowset should not be affecting the NFP what-so-ever...
			TESTC(Rowsets[i].VerifyRowHandles(1, &hRow, FIRST_ROW+i));
		}
		SAFE_RELEASE(pIRowset);
		Rowsets[i].ReleaseRows(hRow);
	}

	//Now that all rows are released, reverify the NFP is unchanged...
	for(i=0; i<cRowsets; i++)
	{
		//Need to release the row object first, since internally it may hold a row handle...
		RowObjects[i].ReleaseRowObject();
		Rowsets[i].ReleaseRows(rghRows[i]);

		//Grab the next row...
		TESTC_(Rowsets[i].GetNextRows(0, 1, &rghRows[i]), S_OK);

		//Verify the position
		TESTC(Rowsets[i].VerifyRowHandles(1, &rghRows[i], FIRST_ROW+i+1));

		//Release the row...
		TESTC_(Rowsets[i].ReleaseRows(rghRows[i]),S_OK);
	}

CLEANUP:
	SAFE_RELEASE(pIRowset);
	TRETURN
}
// }} TCW_VAR_PROTOTYPE_END

// {{ TCW_VAR_PROTOTYPE(15)
//*-----------------------------------------------------------------------
// @mfunc Empty
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCIRow_GetSourceRowset::Variation_15()
{
	return TEST_SKIPPED;
}
// }} TCW_VAR_PROTOTYPE_END

// {{ TCW_VAR_PROTOTYPE(16)
//*-----------------------------------------------------------------------
// @mfunc Aggregation - Rowset -> Agg Row -> GetSourceRowset
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCIRow_GetSourceRowset::Variation_16()
{
	TBEGIN
	HROW hRow = NULL;
    CAggregate Aggregate(pIRowset());
	IUnknown* pIAggregate  = NULL;
	IGetRow* pIGetRow = NULL;
	IRow* pIRow = NULL;
	IUnknown* pIUnkInner = NULL;
	HRESULT hr = S_OK;

	CRowset		RowsetA;
	CRowObject	RowObjectA;

	//Obtain the second row
	TESTC_PROVIDER(m_ulpOleObjects & DBPROPVAL_OO_ROWOBJECT);
	TESTC_(RowsetA.CreateRowset(),S_OK);
	TESTC_(RowsetA.GetRow(SECOND_ROW, &hRow),S_OK);

	//Obtain a row object...
	hr = RowsetA.GetRowFromHROW(&Aggregate, hRow, IID_IUnknown, (IUnknown**)&pIUnkInner);
	Aggregate.SetUnkInner(pIUnkInner);

	//Verify Aggregation for this row...
	TESTC_PROVIDER(Aggregate.VerifyAggregationQI(hr, IID_IRow, (IUnknown**)&pIRow));
	TESTC_(RowObjectA.SetRowObject(pIRow),S_OK);

	//IRow::GetSourceRowset
	TEST2C_( hr = RowObjectA.GetSourceRowset(IID_IAggregate, (IUnknown**)&pIAggregate, NULL),E_NOINTERFACE, DB_E_NOSOURCEOBJECT);
	TEST2C_(hr = RowObjectA.GetSourceRowset(IID_IGetRow,	(IUnknown**)&pIGetRow, NULL), S_OK, DB_E_NOSOURCEOBJECT);

	if(hr==S_OK)
	{
		TESTC(VerifyEqualInterface(RowsetA.pIRowset(), pIGetRow));
	}
	else
	{
		TWARNING(L"IRow::GetSourceRowset unable to retrieve Parent object!");
	}

CLEANUP:
	RowsetA.ReleaseRows(hRow);
	SAFE_RELEASE(pIAggregate);
	SAFE_RELEASE(pIGetRow);
	SAFE_RELEASE(pIRow);
	SAFE_RELEASE(pIUnkInner);
	RowObjectA.ReleaseRowObject();
	Aggregate.ReleaseInner();
	TRETURN
}
// }} TCW_VAR_PROTOTYPE_END

// {{ TCW_VAR_PROTOTYPE(17)
//*-----------------------------------------------------------------------
// @mfunc Aggregation - Agg Rowset -> Row -> GetSourceRowset
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCIRow_GetSourceRowset::Variation_17()
{
	TBEGIN
	HROW hRow = NULL;
    CAggregate Aggregate(pIRowset());
	IRow* pIRow = NULL;
	IGetRow* pIGetRow = NULL;
	IUnknown* pIAggregate  = NULL;
	COpenRowset OpenRowsetA;
	CRowset RowsetA;
	IUnknown* pIUnkInner = NULL;
	ULONG ulRefCountBefore, ulRefCountAfter;

	// Verify that the provider supports IGetRow interface
	TEST_PROVIDER(SupportedInterface(IID_IGetRow,ROWSET_INTERFACE));

	//Create a rowset that is Aggregated...
	HRESULT hr = OpenRowsetA.CreateOpenRowset(IID_IUnknown, (IUnknown**)&pIUnkInner, &Aggregate);
	Aggregate.SetUnkInner(pIUnkInner);

	//Verify Aggregation for this rowset...

	TESTC_PROVIDER(Aggregate.VerifyAggregationQI(hr, IID_IGetRow, (IUnknown**)&pIGetRow));

	//Obtain the second row
	TESTC_(RowsetA.CreateRowset(pIGetRow),S_OK);
	TESTC_(RowsetA.GetRow(SECOND_ROW, &hRow),S_OK);

	//Now Create the Row (non-aggregated)
	//NOTE: The Aggregated row senario (GetRowFromHROW) is done in the IGetRow test since
	//its explicitly interested in that method.  In IRow were maininly interested in testing
	//GetSourceRowset so we need to do the Aggregated Rowset -> Row senario...
	ulRefCountBefore = Aggregate.GetRefCount();
	TEST2C_(hr = pIGetRow->GetRowFromHROW(NULL, hRow, IID_IRow, (IUnknown**)&pIRow),S_OK,DB_S_NOROWSPECIFICCOLUMNS);
	ulRefCountAfter = Aggregate.GetRefCount();

	//IRow::GetSourceRowset
	TEST2C_(hr = pIRow->GetSourceRowset(IID_IAggregate, (IUnknown**)&pIAggregate, NULL),S_OK,DB_E_NOSOURCEOBJECT);

	if(hr==S_OK)
	{
		TESTC(VerifyEqualInterface(pIAggregate, pIGetRow));

		//Verify the child correctly addref'd the parent outer.
		//The is an absolute requirement that the child keep the parent outer alive.
		//If it doesn't addref the outer, the outer can be released externally since
		//its not being used anymore due to the fact the outer controls the refcount
		//of the inner.  Many providers incorrectly addref the inner, which does nothing
		//but guareentee the inner survives, but the inner will delegate to the outer
		//and crash since it no longer exists...
		TCOMPARE_(ulRefCountAfter > ulRefCountBefore);
	}
	else
	{
		TWARNING(L"IRow::GetSourceRowset unable to retrieve Parent object!");
	}

CLEANUP:
	SAFE_RELEASE(pIAggregate);
	SAFE_RELEASE(pIRow);
	SAFE_RELEASE(pIGetRow);
	RowsetA.ReleaseRows(hRow);
	SAFE_RELEASE(pIUnkInner);
	TRETURN
}
// }} TCW_VAR_PROTOTYPE_END

// {{ TCW_VAR_PROTOTYPE(18)
//*-----------------------------------------------------------------------
// @mfunc Empty
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCIRow_GetSourceRowset::Variation_18()
{
	return TEST_SKIPPED;
}
// }} TCW_VAR_PROTOTYPE_END

// {{ TCW_VAR_PROTOTYPE(19)
//*-----------------------------------------------------------------------
// @mfunc Threads - GetSourceRowset
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCIRow_GetSourceRowset::Variation_19()
{
	TBEGIN
	INIT_THREADS(MAX_THREADS);

	//Setup Thread Arguments
	THREADARG T1Arg = { this };

	//Create Threads
	CREATE_THREADS(Thread_VerifyGetSourceRowset, &T1Arg);

	START_THREADS();
	END_THREADS();

	TRETURN
}
// }} TCW_VAR_PROTOTYPE_END

// {{ TCW_TERMINATE_METHOD
//*-----------------------------------------------------------------------
// @mfunc TestCase Termination Routine
//
// @rdesc TEST_PASS or TEST_FAIL
//
BOOL TCIRow_GetSourceRowset::Terminate()
{
// {{ TCW_TERM_BASECLASS_CHECK2
	return(TCIRow::Terminate());
} 	// }}
// }} TCW_TERMINATE_METHOD_END
// }} TCW_TC_PROTOTYPE_END

// {{ TCW_TC_PROTOTYPE(TCIRow_Open)
//*-----------------------------------------------------------------------
//| Test Case:		TCIRow_Open - IRow::Open
//| Created:  	8/5/98
//*-----------------------------------------------------------------------

//*-----------------------------------------------------------------------
// @mfunc TestCase Initialization Routine
//
// @rdesc TRUE or FALSE
//
BOOL TCIRow_Open::Init()
{
	// {{ TCW_INIT_BASECLASS_CHECK
	if(TCIRow::Init())
	// }}
	{
		return TRUE;
	}
	return FALSE;
}

// {{ TCW_VAR_PROTOTYPE(1)
//*-----------------------------------------------------------------------
// @mfunc GUID_NULL - All columns as Default Object
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCIRow_Open::Variation_1()
{
	TBEGIN

	//IRow::Open
	TESTC(VerifyOpenAllRows(NULL, GUID_NULL, IID_IUnknown, ALL_COLS_BOUND));

CLEANUP:
	TRETURN
}
// }} TCW_VAR_PROTOTYPE_END

// {{ TCW_VAR_PROTOTYPE(2)
//*-----------------------------------------------------------------------
// @mfunc DBGUID_STREAM - All Mandatory and Optional TStream interfaces
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCIRow_Open::Variation_2()
{
	TBEGIN

	//Open all columns as Mandatory and Optional stream interfaces
	TESTC(VerifyOpenAllInterfaces(STREAM_INTERFACE, DBGUID_STREAM))

CLEANUP:
	TRETURN
}
// }} TCW_VAR_PROTOTYPE_END

// {{ TCW_VAR_PROTOTYPE(3)
//*-----------------------------------------------------------------------
// @mfunc DBGUID_STREAM - Compare data with expected
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCIRow_Open::Variation_3()
{
	TBEGIN

	//IRow::Open
	TESTC(VerifyOpenAllRows(NULL, DBGUID_STREAM, IID_ISequentialStream, ALL_COLS_BOUND));
	TESTC(VerifyOpenAllRows(NULL, DBGUID_STREAM, IID_IStream, ALL_COLS_BOUND));

CLEANUP:
	TRETURN
}
// }} TCW_VAR_PROTOTYPE_END

// {{ TCW_VAR_PROTOTYPE(4)
//*-----------------------------------------------------------------------
// @mfunc DBGUID_STREAM - Twice on the same column
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCIRow_Open::Variation_4()
{
	TBEGIN

	//Multiple Objects open
	TESTC(VerifyOpenWithOpenObjects(DBGUID_STREAM, IID_ISequentialStream))
	TESTC(VerifyOpenWithOpenObjects(DBGUID_STREAM, IID_IStream))

CLEANUP:
	TRETURN
}
// }} TCW_VAR_PROTOTYPE_END

// {{ TCW_VAR_PROTOTYPE(5)
//*-----------------------------------------------------------------------
// @mfunc DBGUID_STREAM - Multiple Objects open on different columns
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCIRow_Open::Variation_5()
{
	TBEGIN

	//Multiple Objects open
	TESTC(VerifyOpenWithOpenObjects(DBGUID_STREAM, IID_ISequentialStream))
	TESTC(VerifyOpenWithOpenObjects(DBGUID_STREAM, IID_IStream))

CLEANUP:
	TRETURN
}
// }} TCW_VAR_PROTOTYPE_END

// {{ TCW_VAR_PROTOTYPE(6)
//*-----------------------------------------------------------------------
// @mfunc DBGUID_STREAM - Bufferred Mode
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCIRow_Open::Variation_6()
{
	TBEGIN

	//Create a buffered mode rowset
	CRowsetUpdate RowsetA;

	//Not all providers will support IRowsetUpdate
	TESTC_PROVIDER(RowsetA.CreateRowset()==S_OK);

	//IRow::Open
	TESTC(VerifyOpenAllRows(&RowsetA, DBGUID_STREAM, IID_IStream, ALL_COLS_BOUND));

CLEANUP:
	TRETURN
}
// }} TCW_VAR_PROTOTYPE_END

// {{ TCW_VAR_PROTOTYPE(7)
//*-----------------------------------------------------------------------
// @mfunc Empty
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCIRow_Open::Variation_7()
{
	return TEST_SKIPPED;
}
// }} TCW_VAR_PROTOTYPE_END

// {{ TCW_VAR_PROTOTYPE(8)
//*-----------------------------------------------------------------------
// @mfunc DBGUID_ROW - All Mandatory and Optional TRow interfaces
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCIRow_Open::Variation_8()
{
	TBEGIN

	//Open all columns as Mandatory and Optional interfaces
	TESTC(VerifyOpenAllInterfaces(ROW_INTERFACE, DBGUID_ROW))

CLEANUP:
	TRETURN
}
// }} TCW_VAR_PROTOTYPE_END

// {{ TCW_VAR_PROTOTYPE(9)
//*-----------------------------------------------------------------------
// @mfunc DBGUID_ROW - Get all row columns and verify
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCIRow_Open::Variation_9()
{
	TBEGIN

	//IRow::Open
	TESTC(VerifyOpenAllRows(NULL, DBGUID_ROW, IID_IRow, ALL_COLS_BOUND));

CLEANUP:
	TRETURN
}
// }} TCW_VAR_PROTOTYPE_END

// {{ TCW_VAR_PROTOTYPE(10)
//*-----------------------------------------------------------------------
// @mfunc DBGUID_ROW - GetSourceRowset
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCIRow_Open::Variation_10()
{
	TBEGIN

	//IRow::Open
	//This helper will call GetSourceRowset from the returned row object...
	TESTC(VerifyOpenWithOpenObjects(DBGUID_ROW, IID_IRow));

CLEANUP:
	TRETURN
}
// }} TCW_VAR_PROTOTYPE_END

// {{ TCW_VAR_PROTOTYPE(11)
//*-----------------------------------------------------------------------
// @mfunc DBGUID_ROW - Twice on the same column
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCIRow_Open::Variation_11()
{
	TBEGIN

	//Multiple Objects open
	TESTC(VerifyOpenWithOpenObjects(DBGUID_ROW, IID_IRow))

CLEANUP:
	TRETURN
}
// }} TCW_VAR_PROTOTYPE_END

// {{ TCW_VAR_PROTOTYPE(12)
//*-----------------------------------------------------------------------
// @mfunc DBGUID_ROW - Multiple Objects open on different columns
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCIRow_Open::Variation_12()
{
	TBEGIN

	//Multiple Objects open
	TESTC(VerifyOpenWithOpenObjects(DBGUID_ROW, IID_IRow))

CLEANUP:
	TRETURN
}
// }} TCW_VAR_PROTOTYPE_END

// {{ TCW_VAR_PROTOTYPE(13)
//*-----------------------------------------------------------------------
// @mfunc DBGUID_ROW - Bufferred Mode
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCIRow_Open::Variation_13()
{
	TBEGIN

	//Create a buffered mode rowset
	CRowsetUpdate RowsetA;

	//Not all providers will support IRowsetUpdate
	TESTC_PROVIDER(RowsetA.CreateRowset()==S_OK);

	//IRow::Open
	TESTC(VerifyOpenAllRows(&RowsetA, DBGUID_ROW, IID_IRow, ALL_COLS_BOUND));

CLEANUP:
	TRETURN
}
// }} TCW_VAR_PROTOTYPE_END

// {{ TCW_VAR_PROTOTYPE(14)
//*-----------------------------------------------------------------------
// @mfunc Empty
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCIRow_Open::Variation_14()
{
	return TEST_SKIPPED;
}
// }} TCW_VAR_PROTOTYPE_END

// {{ TCW_VAR_PROTOTYPE(15)
//*-----------------------------------------------------------------------
// @mfunc DBGUID_ROWSET - All Mandatory and Optional TRowset interfaces
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCIRow_Open::Variation_15()
{
	TBEGIN

	//Open all columns as Mandatory and Optional interfaces
	TESTC(VerifyOpenAllInterfaces(ROWSET_INTERFACE, DBGUID_ROWSET))

CLEANUP:
	TRETURN
}
// }} TCW_VAR_PROTOTYPE_END

// {{ TCW_VAR_PROTOTYPE(16)
//*-----------------------------------------------------------------------
// @mfunc DBGUID_ROWSET - Twice on the same column
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCIRow_Open::Variation_16()
{
	TBEGIN

	//Multiple Objects open
	TESTC(VerifyOpenWithOpenObjects(DBGUID_ROWSET, IID_IRowset))

CLEANUP:
	TRETURN
}
// }} TCW_VAR_PROTOTYPE_END

// {{ TCW_VAR_PROTOTYPE(17)
//*-----------------------------------------------------------------------
// @mfunc DBGUID_ROWSET - Buffered mode
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCIRow_Open::Variation_17()
{
	TBEGIN

	//Create a buffered mode rowset
	CRowsetUpdate RowsetA;

	//Not all providers will support IRowsetUpdate
	TESTC_PROVIDER(RowsetA.CreateRowset()==S_OK);

	//Multiple Objects open
	TESTC(VerifyOpenAllRows(&RowsetA, DBGUID_ROWSET, IID_IRowset, ALL_COLS_BOUND));

CLEANUP:
	TRETURN
}
// }} TCW_VAR_PROTOTYPE_END

// {{ TCW_VAR_PROTOTYPE(18)
//*-----------------------------------------------------------------------
// @mfunc Empty
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCIRow_Open::Variation_18()
{
	return TEST_SKIPPED;
}
// }} TCW_VAR_PROTOTYPE_END

// {{ TCW_VAR_PROTOTYPE(19)
//*-----------------------------------------------------------------------
// @mfunc DEFAULTSTREAM
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCIRow_Open::Variation_19()
{
	TBEGIN

	//VerifyOpenWithOpenObjects also takes case of the DefaultStream object...
	//TODO: Currently this function doesn't take care of the default stream...
	TESTC(VerifyOpenWithOpenObjects(DBGUID_STREAM, IID_IStream))

CLEANUP:
	TRETURN
}
// }} TCW_VAR_PROTOTYPE_END

// {{ TCW_VAR_PROTOTYPE(20)
//*-----------------------------------------------------------------------
// @mfunc DEFAULTSTREAM - Buffered mode
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCIRow_Open::Variation_20()
{
	TBEGIN

	//Create a buffered mode rowset
	CRowsetUpdate RowsetA;

	//Not all providers will support IRowsetUpdate
	TESTC_PROVIDER(RowsetA.CreateRowset()==S_OK);

	//Multiple Objects open
	TESTC(VerifyOpenAllRows(&RowsetA, DBGUID_STREAM, IID_IStream, ALL_COLS_BOUND));

CLEANUP:
	TRETURN
}
// }} TCW_VAR_PROTOTYPE_END

// {{ TCW_VAR_PROTOTYPE(21)
//*-----------------------------------------------------------------------
// @mfunc Empty
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCIRow_Open::Variation_21()
{
	return TEST_SKIPPED;
}
// }} TCW_VAR_PROTOTYPE_END

// {{ TCW_VAR_PROTOTYPE(22)
//*-----------------------------------------------------------------------
// @mfunc Boundary - E_INVALIDARG
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCIRow_Open::Variation_22()
{
	TBEGIN

	//We want the columnID to be correct, incase the provider validates it before the object type
	const DBID* pColumnID = m_pCRowObject->m_cColAccess ? &m_pCRowObject->m_rgColAccess[0].columnid : &DBROWCOL_DEFAULTSTREAM;

	//NOTE: We have to call directly since our helper handles this...
	TESTC_(m_pCRowObject->pIRow()->Open(NULL, (DBID*)pColumnID, GUID_NULL, 0, IID_IUnknown, NULL), E_INVALIDARG);

CLEANUP:
	TRETURN
}
// }} TCW_VAR_PROTOTYPE_END

// {{ TCW_VAR_PROTOTYPE(23)
//*-----------------------------------------------------------------------
// @mfunc Boundary - DB_E_BADCOLUMNID - invalid DBID
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCIRow_Open::Variation_23()
{
	TBEGIN
	DBID* pColumnID = NULL;
	DBKIND iKind = 0;

	//Obtain a row object
	CRowObject RowObjectA;
	TESTC_(GetRowObject(FIRST_ROW, &RowObjectA), S_OK);
	SAFE_ALLOC(pColumnID, DBID, 1);

	//Loop through all possible DBKINDs
	for(iKind=0; iKind<DBKIND_GUID+1; iKind++)
	{
		//Now Create a unique colid for this type...
		pColumnID->eKind = iKind % (DBKIND_GUID+1);
		TESTC_(CreateUniqueDBID(pColumnID, TRUE/*fInitialize*/),S_OK);

		//DB_E_BADCOLUMNID - invalid DBID
		TESTC_(RowObjectA.Open(NULL, pColumnID, GUID_NULL, IID_IUnknown), DB_E_BADCOLUMNID);

		//Error depends upon order of validation in the provider
		TEST2C_(RowObjectA.Open(NULL, pColumnID, DBGUID_ROWSET, IID_IRowset), DB_E_BADCOLUMNID, DB_E_OBJECTMISMATCH);
		TEST2C_(RowObjectA.Open(NULL, pColumnID, DBGUID_ROW, IID_IRow), DB_E_BADCOLUMNID, DB_E_OBJECTMISMATCH);
		TEST2C_(RowObjectA.Open(NULL, pColumnID, DBGUID_STREAM, IID_ISequentialStream), DB_E_BADCOLUMNID, DB_E_OBJECTMISMATCH);
		ReleaseDBID(pColumnID, FALSE/*fDrop*/);
	}

CLEANUP:
	ReleaseDBID(pColumnID, TRUE/*fDrop*/);
	TRETURN
}
// }} TCW_VAR_PROTOTYPE_END

// {{ TCW_VAR_PROTOTYPE(24)
//*-----------------------------------------------------------------------
// @mfunc Boundary - DB_E_BADCOLUMNID - invalid [but close to original] DBID
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCIRow_Open::Variation_24()
{
	TBEGIN
	DBORDINAL iCol = 0;

	//Obtain a row object
	CRowObject RowObjectA;
	TESTC_(GetRowObject(FIRST_ROW, &RowObjectA), S_OK);

	//Loop through all current columns
	for(iCol=0; iCol<RowObjectA.m_cColAccess; iCol++)
	{
		//NOTE: We can "overwrite" this DBID since were only using this RowObject for this variation
		DBID* pColumnID = &RowObjectA.m_rgColAccess[iCol].columnid;

		//The problem is that for multipart-DBIDs (two part naming), the provider may only validate
		//one and allow to the the other to fall through.
		switch(pColumnID->eKind)
		{
			case DBKIND_GUID_NAME:
			case DBKIND_PGUID_NAME:
			{
				GUID guid;

				//Create a "unique" string
				SAFE_FREE(pColumnID->uName.pwszName);

				//For every other "name" column - well use NULL
				if(iCol%2)
				{
					TESTC_(CoCreateGuid(&guid),S_OK);
					TESTC_(StringFromCLSID(guid, &pColumnID->uName.pwszName),S_OK);
				}
				break;
			}

			default:
			{
				//Otherwise just create a completely unique name...
				//For two-part it changes the GUID, so all we really have left is to verify
				//that only changing the name is caught...
				TESTC_(CreateUniqueDBID(pColumnID, TRUE/*fInitialize*/),S_OK);
				break;
			}
		};

		//DB_E_BADCOLUMNID - invalid DBID
		TESTC_(RowObjectA.Open(NULL, pColumnID, GUID_NULL, IID_IUnknown), DB_E_BADCOLUMNID);

		//Error depends upon order of validation in the provider
		TEST2C_(RowObjectA.Open(NULL, pColumnID, DBGUID_ROWSET, IID_IRowset), DB_E_BADCOLUMNID, DB_E_OBJECTMISMATCH);
		TEST2C_(RowObjectA.Open(NULL, pColumnID, DBGUID_ROW, IID_IRow), DB_E_BADCOLUMNID, DB_E_OBJECTMISMATCH);
		TEST2C_(RowObjectA.Open(NULL, pColumnID, DBGUID_STREAM, IID_ISequentialStream), DB_E_BADCOLUMNID, DB_E_OBJECTMISMATCH);
	}

CLEANUP:
	TRETURN
}
// }} TCW_VAR_PROTOTYPE_END

// {{ TCW_VAR_PROTOTYPE(25)
//*-----------------------------------------------------------------------
// @mfunc Boundary - DB_E_BADCOLUMNID - shortcut DBID that doesn't exist
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCIRow_Open::Variation_25()
{
	TBEGIN
	ULONG i=0;

	//Obtain a row object
	CRowObject RowObjectA;
	TESTC_(GetRowObject(FIRST_ROW, &RowObjectA), S_OK);

	//Loop through all possible DBROWCOLs
	for(i=0; i<g_cRowColMap; i++)
	{
		//S_OK or DB_E_BADCOLUMNID (depending if column is available...)
		//NOTE: The special columns are not returned in colinfo...
		TEST2C_(RowObjectA.Open(NULL, g_rgRowColMap[i].pDBID, GUID_NULL, IID_IUnknown), S_OK, DB_E_BADCOLUMNID);

		//Error depends upon order of validation in the provider
		TEST3C_(RowObjectA.Open(NULL, g_rgRowColMap[i].pDBID, DBGUID_ROWSET, IID_IRowset), S_OK, DB_E_BADCOLUMNID, DB_E_OBJECTMISMATCH);
		TEST3C_(RowObjectA.Open(NULL, g_rgRowColMap[i].pDBID, DBGUID_ROW, IID_IRow), S_OK, DB_E_BADCOLUMNID, DB_E_OBJECTMISMATCH);
		TEST3C_(RowObjectA.Open(NULL, g_rgRowColMap[i].pDBID, DBGUID_STREAM, IID_ISequentialStream), S_OK, DB_E_BADCOLUMNID, DB_E_OBJECTMISMATCH);

		//NOTE: Positive and negative testing are done in the helper.
		//Also beyond that we should be able to obtain data from the special column
		//TODO: Although this would be a bunch of special casing since its not returned in colinfo
		//and would require hard coding the bindings, etc.  (we already do DBGUID_DEFAULTSTREAM else where)
	}

CLEANUP:
	TRETURN
}
// }} TCW_VAR_PROTOTYPE_END

// {{ TCW_VAR_PROTOTYPE(26)
//*-----------------------------------------------------------------------
// @mfunc Boundary - DB_E_OBJECTMISMATCH
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCIRow_Open::Variation_26()
{
	TBEGIN

	//We want the columnID to be correct, incase the provider validates it before the object type
	const DBID* pColumnID = m_pCRowObject->m_cColAccess ? &m_pCRowObject->m_rgColAccess[0].columnid : &DBROWCOL_DEFAULTSTREAM;

	//DB_E_OBJECTMISMATCH - invalid Object type
	TESTC_(m_pCRowObject->Open(NULL, pColumnID, CLSID_MSDASQL, IID_IUnknown), DB_E_OBJECTMISMATCH);

CLEANUP:
	TRETURN
}
// }} TCW_VAR_PROTOTYPE_END

// {{ TCW_VAR_PROTOTYPE(27)
//*-----------------------------------------------------------------------
// @mfunc Boundary - DB_E_OBJECTOPEN
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCIRow_Open::Variation_27()
{
	// TO DO:  Add your own code here
	return TRUE;
}
// }} TCW_VAR_PROTOTYPE_END

// {{ TCW_VAR_PROTOTYPE(28)
//*-----------------------------------------------------------------------
// @mfunc Boundary - DB_E_NOTFOUND
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCIRow_Open::Variation_28()
{
	// TO DO:  Add your own code here
	return TRUE;
}
// }} TCW_VAR_PROTOTYPE_END

// {{ TCW_VAR_PROTOTYPE(29)
//*-----------------------------------------------------------------------
// @mfunc Boundary - DB_E_DELETEDROW
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCIRow_Open::Variation_29()
{
	// TO DO:  Add your own code here
	return TRUE;
}
// }} TCW_VAR_PROTOTYPE_END

// {{ TCW_VAR_PROTOTYPE(30)
//*-----------------------------------------------------------------------
// @mfunc Empty
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCIRow_Open::Variation_30()
{
	return TEST_SKIPPED;
}
// }} TCW_VAR_PROTOTYPE_END

// {{ TCW_VAR_PROTOTYPE(31)
//*-----------------------------------------------------------------------
// @mfunc Stream Object - Read the data in chunks
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCIRow_Open::Variation_31()
{
	TBEGIN
	IUnknown* pIUnknown = NULL;
	ULONG cbRead	= 0;
	ULONG cbTotal	= 0;
	BYTE* rgBytes = NULL;
	BYTE* rgBytes2 = NULL;
	HRESULT hr = S_OK;
	DBID* pColumnID = NULL;

	//Obtain a row object
	CRowObject RowObjectA;
	TESTC_(GetRowObject(FIRST_ROW, &RowObjectA), S_OK);

	//Obtain a stream object
	if(SUCCEEDED(FindObject(&RowObjectA, NULL, DBGUID_STREAM, IID_IUnknown, &pIUnknown, &pColumnID)))
	{
		//First read the stream (in chunks)...
		while(SUCCEEDED(hr))
		{
			SAFE_REALLOC(rgBytes, BYTE, cbTotal + 10);
			TEST2C_(hr = StorageRead(IID_IUnknown, pIUnknown, rgBytes + cbTotal, 10, &cbRead),S_OK,S_FALSE);
			cbTotal += cbRead;

			if(cbRead == 0)
				break;
		}

		//Now close the stream and open it again
		//NOTE: We have to completely recreate the row object, since the Data could be Forward-Only...
		SAFE_RELEASE(pIUnknown);
		TESTC_(GetRowObject(FIRST_ROW, &RowObjectA), S_OK);

		//Obtain the stream again
		TESTC_(RowObjectA.Open(NULL, pColumnID, DBGUID_STREAM, IID_IUnknown, &pIUnknown),S_OK);

		//Now a third of the bytes (should succeed, not at the end)
		SAFE_REALLOC(rgBytes2, BYTE, cbTotal/3);
		TESTC_(hr = StorageRead(IID_IUnknown, pIUnknown, rgBytes2, cbTotal/3, &cbRead), S_OK);
		TESTC(cbTotal/3 == cbRead);

		//Make sure these are are the same as the first read
		TESTC(memcmp(rgBytes, rgBytes2, cbRead)==0);

		//Now close the stream before all the data is read, and reopen it...
		SAFE_RELEASE(pIUnknown);
		TEST2C_(hr = RowObjectA.Open(NULL, pColumnID, DBGUID_STREAM, IID_IUnknown, &pIUnknown),S_OK, DB_E_COLUMNUNAVAILABLE);
		if(SUCCEEDED(hr))
		{
			//Read again - this should return the data starting at the begining, not where the
			//previous stream left off (common mistake).  This should be idential to GetData/GetColumns
			//when called again returns the data again.
			SAFE_REALLOC(rgBytes2, BYTE, cbTotal+1);
			TEST2C_(hr = StorageRead(IID_IUnknown, pIUnknown, rgBytes2, cbTotal+1, &cbRead), S_OK, S_FALSE);
			TESTC(cbTotal == cbRead);

			//Compare the data to the original returned.
			TESTC(memcmp(rgBytes, rgBytes2, cbRead)==0);
		}
		else
		{
			TWARNING("Provider doesn't support reading the data twice...");
		}
	}
	else
	{
		TWARNING("Unable to open any stream object on the row?");
	}

CLEANUP:
	ReleaseDBID(pColumnID);
	SAFE_RELEASE(pIUnknown);
	SAFE_FREE(rgBytes);
	TRETURN
}
// }} TCW_VAR_PROTOTYPE_END

// {{ TCW_VAR_PROTOTYPE(32)
//*-----------------------------------------------------------------------
// @mfunc Empty
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCIRow_Open::Variation_32()
{
	// TO DO:  Add your own code here
	return TRUE;
}
// }} TCW_VAR_PROTOTYPE_END

// {{ TCW_VAR_PROTOTYPE(33)
//*-----------------------------------------------------------------------
// @mfunc Aggregation - Row -> Open -> GetSourceRow
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCIRow_Open::Variation_33()
{
	TBEGIN
	HRESULT hr = S_OK;
	DBORDINAL i,cColAccess = 0;
	DBCOLUMNACCESS* rgColAccess = NULL;
	void* pData = NULL;
	IUnknown* pUnkInner = NULL;
	CAggregate Aggregate;

	//NOTE: The Aggregated Row object senario (Agg Row -> Open -> GetSourceRow) is handled
	//in the GetSourceRow test.  In this senario we are mainly interested in have the object
	//opened aggregated, hence the reason for testing IRow::Open...

	//Obtain a row object
	CRowObject RowObjectA;
	TESTC_(GetRowObject(FIRST_ROW, &RowObjectA), S_OK);

	//Create the ColAccess Structures...
	TESTC_(hr = RowObjectA.CreateColAccess(&cColAccess, &rgColAccess, &pData),S_OK);

	//IRow::Open (for all bound columns)
	for(i=0; i<cColAccess; i++)
	{
		DBTYPE wBaseType = rgColAccess[i].wType & ~(DBTYPE_BYREF | DBTYPE_ARRAY | DBTYPE_VECTOR);

		//First verify the invalid senario (asking for non-IUnknown with Aggregation)
		TESTC_(hr = RowObjectA.Open(&Aggregate, &rgColAccess[i].columnid, GUID_NULL, IID_IRow, &pUnkInner),DB_E_NOAGGREGATION);

		//Open wil mainly only be able to be called for columns containing objects.
		//But some providers might be able to open streams, or other types of objects ontop
		//of non-object valued columns.
		hr = RowObjectA.Open(&Aggregate, &rgColAccess[i].columnid, GUID_NULL, IID_IUnknown, &pUnkInner);
		Aggregate.SetUnkInner(pUnkInner);
		TEST4C_(hr, S_OK, DB_E_NOTFOUND, DB_E_OBJECTMISMATCH, DB_E_NOAGGREGATION);

		if(SUCCEEDED(hr))
		{
			//You should only be able to aggregate object valued columns.
			TESTC(wBaseType==DBTYPE_IUNKNOWN || wBaseType==DBTYPE_IDISPATCH);

			//Verify Aggregation
			TESTC(Aggregate.VerifyAggregationQI(hr, IID_ISequentialStream));
		}
		else
		{
			if(hr == DB_E_NOAGGREGATION)
			{
				//You should be able to aggregate object valued columns, unless the provider
				//has already created them or is for some reason unable to recreate them...
				if(wBaseType==DBTYPE_IUNKNOWN || wBaseType==DBTYPE_IDISPATCH)
					TOUTPUT("WARNING:  IUnknown column ( " << i << ") unable to be aggregated with IRow::Open()");
			}
			else
			{
				if(hr == DB_E_OBJECTMISMATCH)
				{
					TESTC(!(wBaseType==DBTYPE_IUNKNOWN || wBaseType==DBTYPE_IDISPATCH));
				}
				else
				{
					//Column data must be null?
				}
			}
		}

		Aggregate.ReleaseInner();
	}

	//DBROWCOL_DEFAULTSTREAM
	//Now that we have done the returned columns, lets also see if there is a default stream object.
	TEST4C_(hr = RowObjectA.Open(&Aggregate, &DBROWCOL_DEFAULTSTREAM, DBGUID_STREAM, IID_IStream), S_OK, DB_E_NOTFOUND, DB_E_BADCOLUMNID, DB_E_NOAGGREGATION);
	Aggregate.SetUnkInner(pUnkInner);

	//Verify Aggregation
	if(SUCCEEDED(hr))
		TESTC(Aggregate.VerifyAggregationQI(hr, IID_ISequentialStream));

CLEANUP:
	FreeColAccess(cColAccess, rgColAccess);
	SAFE_FREE(pData);
	SAFE_RELEASE(pUnkInner);
	Aggregate.ReleaseInner();
	TRETURN
}
// }} TCW_VAR_PROTOTYPE_END

// {{ TCW_VAR_PROTOTYPE(34)
//*-----------------------------------------------------------------------
// @mfunc Empty
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCIRow_Open::Variation_34()
{
	return TEST_SKIPPED;
}
// }} TCW_VAR_PROTOTYPE_END

// {{ TCW_VAR_PROTOTYPE(35)
//*-----------------------------------------------------------------------
// @mfunc Threads - Open over the same column
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCIRow_Open::Variation_35()
{
	TBEGIN

	INIT_THREADS(MAX_THREADS);

	CRowObject rgRowObjects[MAX_THREADS];

	bool fDifferentColumns = false;
	THREADARG T1Arg = { this, (void*)&GUID_NULL, (void*)&IID_IUnknown, rgRowObjects, rgThreadID, &fDifferentColumns };

	for (int i = 0; i < MAX_THREADS; ++i)
	{
		TESTC_(GetRowObject(FIRST_ROW, &(rgRowObjects[i])), S_OK);
	}

	CREATE_THREADS(Thread_VerifyOpenWithOpenObjects, &T1Arg);

	START_THREADS();
	END_THREADS();

CLEANUP:

	TRETURN
}
// }} TCW_VAR_PROTOTYPE_END

// {{ TCW_VAR_PROTOTYPE(36)
//*-----------------------------------------------------------------------
// @mfunc Threads - Open over different columns
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCIRow_Open::Variation_36()
{
	TBEGIN
	INIT_THREADS(MAX_THREADS);

	CRowObject rgRowObjects[MAX_THREADS];

	bool fDifferentColumns = true;
	THREADARG T1Arg = { this, (void*)&GUID_NULL, (void*)&IID_IUnknown, rgRowObjects, rgThreadID, &fDifferentColumns };

	for (int i = 0; i < MAX_THREADS; ++i)
	{
		TESTC_(GetRowObject(FIRST_ROW, &(rgRowObjects[i])), S_OK);
	}

	CREATE_THREADS(Thread_VerifyOpenWithOpenObjects, &T1Arg);

	START_THREADS();
	END_THREADS();

CLEANUP:

	TRETURN
}
// }} TCW_VAR_PROTOTYPE_END

// {{ TCW_TERMINATE_METHOD
//*-----------------------------------------------------------------------
// @mfunc TestCase Termination Routine
//
// @rdesc TEST_PASS or TEST_FAIL
//
BOOL TCIRow_Open::Terminate()
{
// {{ TCW_TERM_BASECLASS_CHECK2
	return(TCIRow::Terminate());
} 	// }}
// }} TCW_TERMINATE_METHOD_END
// }} TCW_TC_PROTOTYPE_END

// {{ TCW_TC_PROTOTYPE(TCTransactions)
//*-----------------------------------------------------------------------
//| Test Case:		TCTransactions - IRow inside Transactions
//| Created:  	8/5/98
//*-----------------------------------------------------------------------

//*-----------------------------------------------------------------------
// @mfunc TestCase Initialization Routine
//
// @rdesc TRUE or FALSE
//
BOOL TCTransactions::Init()
{
	if(CTransaction::Init())
	{
	   	//register interface to be tested
		TEST_PROVIDER(SupportedInterface(IID_IGetRow,ROWSET_INTERFACE));
		if(RegisterInterface(ROWSET_INTERFACE, IID_IGetRow, 0, NULL))
			return TRUE;
	}

	//Not all providers have to support transactions
	//If a required interface, an error would have been posted by VerifyInterface
	TEST_PROVIDER(m_pITransactionLocal != NULL);
	return FALSE;
}

// {{ TCW_VAR_PROTOTYPE(1)
//*-----------------------------------------------------------------------
// @mfunc ABORT with fRetaining TRUE
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCTransactions::Variation_1()
{
	return VerifyTransaction(FALSE/*fCommit*/, TRUE/*fRetaining*/);
}
// }} TCW_VAR_PROTOTYPE_END

// {{ TCW_VAR_PROTOTYPE(2)
//*-----------------------------------------------------------------------
// @mfunc ABORT with fRetaining FALSE
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCTransactions::Variation_2()
{
	return VerifyTransaction(FALSE/*fCommit*/, FALSE/*fRetaining*/);
}
// }} TCW_VAR_PROTOTYPE_END

// {{ TCW_VAR_PROTOTYPE(3)
//*-----------------------------------------------------------------------
// @mfunc COMMIT with fRetaining TRUE
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCTransactions::Variation_3()
{
	return VerifyTransaction(TRUE/*fCommit*/, TRUE/*fRetaining*/);
}
// }} TCW_VAR_PROTOTYPE_END

// {{ TCW_VAR_PROTOTYPE(4)
//*-----------------------------------------------------------------------
// @mfunc COMMIT with fRetaining FALSE
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCTransactions::Variation_4()
{
	return VerifyTransaction(FALSE/*fCommit*/, FALSE/*fRetaining*/);
}
// }} TCW_VAR_PROTOTYPE_END

// {{ TCW_TERMINATE_METHOD
//*-----------------------------------------------------------------------
// @mfunc TestCase Termination Routine
//
// @rdesc TEST_PASS or TEST_FAIL
//
BOOL TCTransactions::Terminate()
{
// {{ TCW_TERM_BASECLASS_CHECK2
	return(CTransaction::Terminate());
} 	// }}
// }} TCW_TERMINATE_METHOD_END
// }} TCW_TC_PROTOTYPE_END

{'repo_name': 'pauldotknopf/WindowsSDK7-Samples', 'stars': '277', 'repo_language': 'C++', 'file_name': 'version.rc2', 'mime_type': 'text/x-c', 'hash': 5904969562335330931, 'source_dataset': 'data'}