//--------------------------------------------------------------------
// Microsoft OLE DB Test
//
// Copyright 1995-2000 Microsoft Corporation.
//
// @doc 
//
// @module ITblDef.CPP | Source for ITableDefinition test module
//
#define  DBINITCONSTANTS	// Must be defined to initialize constants in OLEDB.H
#define  INITGUID

#include "modstandard.hpp"
#include "itbldef.h"
#include "Extralib.h"
#include <initguid.h>

#include <process.h>
#include "clib.hpp"

#include "DataSource.hpp"

const ULONG cMaxName = 300;

// maximum columns allowed per constraint
const DBORDINAL		cMaxColsPerCons			=		16;

// Maximum combined column length of constraint
const DBORDINAL		cMaxColLengthPerCons	=		900;

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Module Values
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// {{ TCW_MODULE_GLOBALS
DECLARE_MODULE_CLSID = { 0xae3d5c1e, 0x2a0b, 0x11d1, { 0xaf, 0x9d, 0x00, 0xc0, 0x4f, 0xc2, 0x27, 0x93 }};
DECLARE_MODULE_NAME("ITableDefinition");
DECLARE_MODULE_OWNER("Microsoft");
DECLARE_MODULE_DESCRIP("The module tests the ITableDefinition interface");
DECLARE_MODULE_VERSION(795921705);
// TCW_WizardVersion(2)
// TCW_Automation(True)
// }} TCW_MODULE_GLOBALS_END
GUID	guidModule	= { 0xae3d5c1e, 0x2a0b, 0x11d1, { 0xaf, 0x9d, 0x00, 0xc0, 0x4f, 0xc2, 0x27, 0x93 }};

//Globals
BOOL				g_fSQLOLEDB25					= FALSE;

// macros
#define FILL_PROP_SET(RGPROPSET_EL, NPROP, RGPROP, PROP_GUID)		\
	RGPROPSET_EL.cProperties		= NPROP;						\
	RGPROPSET_EL.rgProperties		= RGPROP;						\
	RGPROPSET_EL.guidPropertySet	= PROP_GUID;					\
	if (NULL != RGPROP)												\
		memset(RGPROP, 0, NPROP*sizeof(DBPROP));

#define FILL_PROP(RGPROP_EL, PROPID, VAR_TYPE, VAR_MACRO, VAR_VALUE, OPTION)		\
	memset(&RGPROP_EL, 0, sizeof(DBPROP));											\
	RGPROP_EL.dwPropertyID			= PROPID;										\
	RGPROP_EL.vValue.vt				= VAR_TYPE;										\
	VAR_MACRO(&RGPROP_EL.vValue)	= VAR_VALUE;									\
	RGPROP_EL.dwOptions				= OPTION;

#define INVALID_DBKIND	1001

class TCITableDefinition;
class CTransactionLocal;
class CAddUniqueConsTxnAdapter;

// define argument stru for threading function parameters
typedef struct inparam{
	ULONG				i;
	TCITableDefinition	*pObject;
} CInParam;

// the number of threads that will be created in the multithreading test variations
const int nThreads = 7; // must be less than 100 and greater than 1
// the dispatcher thread function
unsigned WINAPI ThreadProc(LPVOID lpvThreadParam);

void			ReleaseAllColumnPropSets(
					DBCOLUMNDESC	*rgColumnDesc,	// [in]	aray to be release
					DBORDINAL		cColumnDesc		// [in] no of elementrs in the array
				);

ULONG	nResidualTables;

//--------------------------------------------------------------------
// @func Module level initialization routine
//
// @rdesc Success or Failure
// 		@flag  TRUE  | Successful initialization
//		@flag  FALSE | Initialization problems
//
BOOL ModuleInit(CThisTestModule * pThisTestModule)
{
	TBEGIN;
	ITableDefinition	*pITableDefinition = NULL;
	HRESULT				hr;

	nResidualTables = 0;

	//Create the session
	if(!ModuleCreateDBSession(pThisTestModule))
		return FALSE;

	g_pIOpenRowset = (IOpenRowset*)pThisTestModule->m_pIUnknown2;
	CConsDesc::s_pSessionIUnknown	= g_pIOpenRowset;
	CConsDesc::s_pDSOIUnknown		= pThisTestModule->m_pIUnknown;
	CConsDesc::s_pConstraints		= new CConstraints(g_pIOpenRowset);
	CConsDesc::s_fInsideTransaction = FALSE;

	if (!(hr=VerifyInterface(pThisTestModule->m_pIUnknown2, IID_ITableDefinition, 
				SESSION_INTERFACE, (IUnknown**)&pITableDefinition)))
	{
		odtLog << "ITableDefinition not supported!\n";
		TESTB = TEST_SKIPPED;;
		goto CLEANUP;
	}

	if (!(hr=VerifyInterface(pThisTestModule->m_pIUnknown, IID_IDBInitialize, 
				DATASOURCE_INTERFACE, (IUnknown**)&g_pIDBInitialize)))
	{
		odtLog << "IDBInitialize not supported!\n";
		TESTB = TEST_SKIPPED;
		goto CLEANUP;
	}

	if (IsSQLProvider())
	{
		if (GetModInfo()->GetProviderVer() && wcsncmp(GetModInfo()->GetProviderVer(), L"07", 2)==0)
			g_fSQLOLEDB25 = TRUE;
	}

CLEANUP:
	SAFE_RELEASE(pITableDefinition);
	TRETURN;
}	
  
//--------------------------------------------------------------------
// @func Module level termination routine
//
// @rdesc Success or Failure
// 		@flag  TRUE  | Successful initialization
//		@flag  FALSE | Initialization problems
//
BOOL ModuleTerminate(CThisTestModule * pThisTestModule)
{
	SAFE_DELETE( CConsDesc::s_pConstraints);
	CConsDesc::s_pSessionIUnknown	= NULL;
	CConsDesc::s_pDSOIUnknown		= NULL;
	if (0 < nResidualTables)
		odtLog << "Total number of residual tables: " << nResidualTables << "\n";
	SAFE_RELEASE(g_pIDBInitialize);

	CCheckConsRowset::s_fMetadataInitialized		= FALSE;
	CCheckConsRowset::s_fSchemaSupported			= FALSE;
	CCheckConsRowset::s_fConsCatalogR				= FALSE;
	CCheckConsRowset::s_fConsSchemaR				= FALSE;
	CCheckConsRowset::s_fConsNameR					= FALSE;

	CPKRowset::s_fMetadataInitialized				= FALSE;
	CPKRowset::s_fSchemaSupported					= FALSE;
	CPKRowset::s_fTableCatalogR						= FALSE;
	CPKRowset::s_fTableSchemaR						= FALSE;
	CPKRowset::s_fTableNameR						= FALSE;

	CFKRowset::s_fMetadataInitialized				= FALSE;
	CFKRowset::s_fSchemaSupported					= FALSE;
	CFKRowset::s_fTableCatalogR						= FALSE;
	CFKRowset::s_fTableSchemaR						= FALSE;
	CFKRowset::s_fTableNameR						= FALSE;

	CKeyColumnUsageRowset::s_fMetadataInitialized	= FALSE;
	CKeyColumnUsageRowset::s_fSchemaSupported		= FALSE;
	CKeyColumnUsageRowset::s_fTableCatalogR			= FALSE;
	CKeyColumnUsageRowset::s_fTableSchemaR			= FALSE;
	CKeyColumnUsageRowset::s_fTableNameR			= FALSE;
	CKeyColumnUsageRowset::s_fConsCatalogR			= FALSE;
	CKeyColumnUsageRowset::s_fConsSchemaR			= FALSE;
	CKeyColumnUsageRowset::s_fConsNameR				= FALSE;

	return ModuleReleaseDBSession(pThisTestModule);
}	

//--------------------------------------------------------------------------
// Given DBCOLUMNDESC, returns the Type name.
//--------------------------------------------------------------------------
WCHAR* GetColumnTypeName(DBCOLUMNDESC *pColumnDesc)
{
	return pColumnDesc->pwszTypeName;
}

//--------------------------------------------------------------------------
//
// release the property of all columns
//--------------------------------------------------------------------------
void ReleaseAllColumnPropSets(
	DBCOLUMNDESC	*rgColumnDesc,	// [in]	aray to be release
	DBORDINAL		cColumnDesc		// [in] no of elementrs in the array
)
{
	ULONG	i;

	if (	(NULL == rgColumnDesc) ||
			(0 == cColumnDesc))
		return;

	for (i=0; i<cColumnDesc; i++)
	{
		FreeProperties(&rgColumnDesc[i].cPropertySets, &rgColumnDesc[i].rgPropertySets);
		ASSERT(0 == rgColumnDesc[i].cPropertySets);
		ASSERT(NULL == rgColumnDesc[i].rgPropertySets);
	}
} //ReleaseAllColumnPropSets

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


//--------------------------------------------------------------------
// @class Base Class
//
class TCITableDefinition : public CSessionObject {
protected:
	// add critical section
	CRITICAL_SECTION	m_CriticalSection; 

	// used to check for residual tables
	ULONG				m_nTables;	

	// @cmember pointer to ITableDefinition interface
	ITableDefinition	*m_pITableDefinition;
	ITableDefinitionWithConstraints	*m_pITDWC;
	BOOL				m_fIsIDBInfo;
	// @cmember list of CCol storing info about provider data types
	CList <CCol, CCol&>	m_ColList;

	// @cmember data about table and column name
	ULONG				m_cMaxTableName, m_cMaxColName;
	LPOLESTR			m_pwszInvalidTableChars;
	LPOLESTR			m_pwszInvalidColChars;
	
	// @cmember array of column descriptors on the table (limited operations on it)
	DBCOLUMNDESC		*m_rgColumnDesc;
	DBORDINAL			m_cColumnDesc;

	// @cmembe aray of result for multithreading processing
	HRESULT				m_rgResult[nThreads];
	// @cmember array of table name for multithreading
	LPWSTR				m_rgName[nThreads];

	DBMATCHTYPE			m_SupportedMatchType;

	// @cmember Check the result and property status
	BOOL	CheckPropertyStatus(
		GUID		guidPropertySet,	// [in]	property set guid 
		GUID		guidExpectedPS,		// [in] expected prop set guid
		DBPROP		*pProp,				// [in]	property
		HRESULT		hr					// [in] the result
	);

	// @cmember Check the prop status of a list of col desc
	BOOL	CheckColPropStatus(
		DBORDINAL		cColDesc,			// [in] 
		DBCOLUMNDESC	*rgColDesc,			// [in] the size of the propset array
		HRESULT			hr					// [in]	the result of the previous op
	);


	// @cmember Drops the column and checks the result
	HRESULT	DropColumnAndCheck(
		DBID				*pTableID,					// [in]		the table ID
		DBID				*pColumnID,					// [in]		the ID of the column to be dropped
		ITableDefinition	*pITableDefinition = NULL,	// [in] pointer to ITableDefinition interface
		DBID				*pBaseTableID = NULL		// [in] if pTableID is exotic (e.g. fuly qualified) use this
	);

	// @cmember Drops the table and checks the result
	HRESULT DropTableAndCheck( 
		DBID				*pTableID,					// [in] ID of the table to be dropped
		ITableDefinition	*pITableDefinition = NULL	// [in] pointer to ITableDefinition interface
	);

	// @cmember Gets literal info about tables and columns
	HRESULT	GetLiteralInfo();

	// @cmember Gets the catalog and schema name for a given table
	BOOL	GetCatalogSchemaNames(
		LPWSTR	pwszTableName,		// [in] the name of the table
		LPWSTR	*ppwszCatalogName,	// [out] catalog name
		LPWSTR	*ppwszSchemaName,	// [out] schema name
		CTable	*pTable	= NULL		// [in]		table object (DEFAULT NULL - use m_pTable)
		);

	// @cmember Check whether the array of ColumnDesc sent was preserved
	// all the data should be inside, the only thing that is allowed to be modified <nl>
	// is the property status
	BOOL	IsColumnDescPreserved
	(
		DBCOLUMNDESC	*rgInColumnDesc,	// the array passed to ITableDefinition
		DBCOLUMNDESC	*rgOutColumnDesc,	// the aray returned by ITableDefinition
		DBORDINAL		cColumnDesc			// the size of the arrays
	);

	// @cmember Build a valid table name of a certain length
	WCHAR*	BuildValidName(size_t, WCHAR*);

	// @cmember Build an invalid table name of a certain length
	WCHAR*	BuildInvalidName(size_t, WCHAR*, WCHAR*);

	// @cmember Uses m_pTable to get a column description mentioning all the provider types
	void	GetProviderTypes(void);

	// @cmember Passes a type name and retrieves the column from m_ColList with info about that type
	CCol	GetType(WCHAR *pwszTypeName, DBTYPE wType, BOOL *fExists=NULL);

	// @cmember Sets all the columns to maximum size as got from m_ColList (from PROVIDER_TYPES Rowset)
	BOOL	SetMaximumColSize(DBCOLUMNDESC*, DBORDINAL);

	// @cmember Sets all the column sizes to 0 
	BOOL	SetZeroColSize(DBCOLUMNDESC*, DBORDINAL);

	// @cmember Set a default property in the property sets of a DBCOLUMNDESC
	BOOL	SetDefaultProperty(
				DBPROPSET		**prgPropertySets,						// [in/out]		array of property sets
				ULONG			*pcPropertySets,						// [in/out]		number of property sets
				VARIANT			*pvalue,								// [in]			property value
				DBPROPOPTIONS	dwOption = DBPROPOPTIONS_OPTIONAL,		// [in]			prop options
				DBID			colid = DB_NULLID,						// [in]			col id
				GUID			guidPropertySet = DBPROPSET_COLUMN,		// [in]			the GUID of the propset
				ULONG			*pcPropSet = NULL,						// [out]		index of property set 
				ULONG			*pcProp =NULL							// [out]		index in the rgProperties array
	);

	// @cmember Compare the list of old columns against the list of new columns and the new column
	BOOL	CheckColInfo(DBCOLUMNDESC*, DBORDINAL, DBCOLUMNDESC*, DBORDINAL, DBCOLUMNDESC*);

	// @cmember Compare the list of old columns against the list of new columns 
	BOOL	AreColEqual(DBCOLUMNDESC*, DBORDINAL, DBCOLUMNDESC*, DBORDINAL);

	// @cmember CheckReturnedDBID about the columns in the table
	//	pIndexID		-	[IN] the DBID asked for
	//	ppIndexID		-	[IN] the DBID created
	BOOL	CheckReturnedDBID(
				DBID	*pIndexID,		// passed to CreateIndex
				DBID	**ppIndexID		// returned by CreateIndex
	);

	// @member Add a column using ITableDefinition::AddColumn and check its addition
	HRESULT	AddColumnAndCheck(
			DBID				*pTableID,					// [IN]  table ID
			DBCOLUMNDESC		*pColumnDesc,				// [IN]  descriptor of the column to be added
			DBID				**ppColumnID,				// [OUT] column ID for the resulted column
			ITableDefinition	*pITableDefinition = NULL,	// [IN]  pointer to ITableDefinition 
			DBID				*pBaseTableID = NULL
	);

	// @member Check properties on rowseet and table
	BOOL	CheckRwstTblPropStatus(
		ULONG			cPropSet,			// [in] the size of the propset array
		DBPROPSET		*rgPropSet,			// [in] propset array
		HRESULT			hr					// [in]	the result of the previous op
	);

	// @member Create the table using ITableDefinition::CreateTable and check its creation
	// then drops the table
	HRESULT	CCNDropTable(
		DBID			*pTableID,			// [in]	pointer to the input table ID
		DBORDINAL		cColumnDescs,		// [in]	the number of columns to be created
		DBCOLUMNDESC	*rgColumnDesc,		// [in/out] array of columns to be created
		REFIID			riid,				// [in] rowset interface to be returned
		ULONG			cPropertySets,		// [in] number of roset property sets asked
		DBPROPSET		*rgPropertySets,	// [in/out] array of rowset property sets
		BOOL			fNullPPTableID = FALSE				// [in] if TRUE ppTableID will be NULL
	);
						
	// @cmember Check whether the columns were properly created
	// The columns of the m_pTable are checked against the column descriptor array <nl>
	// returned by ITableDefinition::CreateTable method. 
	BOOL	AreColumnsCreatedOK(
		DBCOLUMNDESC	*rgOutColumnDesc,	// [in] the aray returned by ITableDefinition::CreateTable
		DBORDINAL		cColumnDesc,		// [in] the size of the arrays
		DBID			*pTableID = NULL,	// [in] Table ID of the table that is checked
		IUnknown		*pIUnknown = NULL					// [in] pointer to a rowset interface on the table
	);
						

	// @cmember Check whether the property sets asked for rowset was preserved
	// all the data should be inside, the only thing that is allowed to be modified <nl>
	// is the property status
	BOOL	IsRowsetPropSetPreserved
	(
		DBPROPSET	*rgInPropertySets,	// the array passed to ITableDefinition::CreateTable
		DBPROPSET	*rgOutPropertysets,	// the aray returned by ITableDefinition::CreateTable
		ULONG		cPropertySets			// the size of the arrays
	);
						

	// @cmember Check whether the rowset properties were properly created
	// The rowset properties of the m_pTable are checked against the property set<nl>
	// returned by ITableDefinition::CreateTable method. 
	BOOL	IsRowsetPropSetCreatedOK
	(
		DBPROPSET	*rgOutPropertySets,		// the aray returned by ITableDefinition::CreateTable
		ULONG		cPropertySets,			// the size of the arrays
		IUnknown	*pIUnknown				// pointer to rowset interface
	);
				
	
	// @cmember Creates a table with a column of each provider type and returns a rowset
	// to the new created table. The rowset is created with the properties required and it
	// is tested
	BOOL	CreateWithRowsetProps
	(
		ULONG			nProperties,			// number of the properties to be set
		DBPROPID		*rgPropID,				// array with the propIDs
		DBTYPE			*rgDBType,				// type of property values			
		LPVOID			*rgValue,				// values to be set
		DBPROPOPTIONS	*rgOptions,				// options of properties
		struct _GUID	*pRIID					// interface asked on rowset
	);


	// @cmember Creates a table with a column of each provider type and returns a rowset
	// to the new created table. The rowset is created with the property required and it
	// is tested
	int	CreateWithOneRowsetProps
	(
		DBPROPID		PropID,				// Property ID
		DBTYPE			DBType,				// type of property value
		LPVOID			Value,				// value to be set
		struct _GUID	*pRIID				// interface asked on rowset
	);

public:

	HRESULT		AddUniqueConstraint(
		CTable				*pTable, 
		DBORDINAL			ulCol,
		DBDEFERRABILITY		Deferrability		= 0
	);

	HRESULT		AddUniqueConstraint(
		CTable				*pTable, 
		DBORDINAL			cCol,
		DBORDINAL			*rgCol,
		DBDEFERRABILITY		Deferrability		= 0
	);

	HRESULT		AddPrimaryKeyConstraint(
		CTable		*pTable, 
		DBORDINAL	ulCol,
		DBDEFERRABILITY		Deferrability		= 0
	);

	HRESULT		AddPrimaryKeyConstraint(
		CTable		*pTable, 
		DBORDINAL	cCol,
		DBORDINAL	*rgCol,
		DBDEFERRABILITY		Deferrability		= 0
	);

	HRESULT		AddKeyConstraint(
		DBCONSTRAINTTYPE	ConstraintType,
		CTable				*pTable, 
		DBORDINAL			cCol,
		DBORDINAL			*rgCol,
		DBDEFERRABILITY		Deferrability		= 0
	);

	HRESULT		AddForeignKeyConstraint(
		CTable				*pBaseTable, 
		DBORDINAL			cBaseCol,
		DBORDINAL			*rgBaseCol,
		CTable				*pReferencedTable, 
		DBORDINAL			cReferencedCol,
		DBORDINAL			*rgReferencedCol,
		DBMATCHTYPE			MatchType,
		DBUPDELRULE			UpdateRule			= DBUPDELRULE_NOACTION,
		DBUPDELRULE			DeleteRule			= DBUPDELRULE_NOACTION,
		DBDEFERRABILITY		Deferrability		= 0
	);

	ITableDefinition				*pITableDefinition() {return m_pITableDefinition;}
	ITableDefinitionWithConstraints	*pITDWC() {return m_pITDWC;}

	DBMATCHTYPE						SupportedMatchType() {
										return m_SupportedMatchType;
	}

	// @member Add a constraint to a table using ITableDefinitionWithConstraints::AddConstraint and check its creation
	HRESULT	AddConstraintAndCheck(
		ITableDefinitionWithConstraints		*pITableDefinitionWithConstraints,	// [in] pointer to the ITableDefinitionWithConstraints interface to be used
		DBID								*pTableID,							// [in]	pointer to the input table ID
		DBCONSTRAINTDESC					*pConstraintDescs,					// [in] new constraint
		BOOL								fDifferentColTypesInFK = FALSE
	);

	// @member Drop a constraint to a table using ITableDefinitionWithConstraints::DropConstraint and check its deletion
	HRESULT	DropConstraintAndCheck(
		ITableDefinitionWithConstraints		*pITableDefinitionWithConstraints,	// [in] pointer to the ITableDefinitionWithConstraints interface to be used
		DBID								*pTableID,							// [in]	pointer to the input table ID
		DBID								*pConstraintID						// [in] pointer to the DBID of the constraint
	);

	// @cmember Start a local transaction using the interface pointer passed
	HRESULT	StartTransaction(ITransactionLocal *pITransactionLocal);

	// @cmember Fills in a variant with whatever it needs
	BOOL	FillVariant(VARIANT *pVariant);

	// @cmember Builds a default value for a given column type
	BOOL	GetDefaultValue(
		DBCOLUMNDESC	*pColumnDesc,	// [in]		column for which the default is build
		VARIANT			*pVariant,		// [out]	variant that contains the default value
		CTable			*pTable=NULL	// [in]		CTable to use
		);

	// @cmember CompareColumnDesc
	// check the new column (first parameter against the result of 
	BOOL	CompareColumnDesc(DBCOLUMNDESC*, DBCOLUMNDESC*);

	// @cmember Compare 2 columns got by GetColumnDescOnTable
	BOOL	AreColEqual(DBCOLUMNDESC*, DBCOLUMNDESC *);

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

	virtual unsigned MyThreadProc(ULONG i) {return i;}

	//constructor
	TCITableDefinition(WCHAR *wstrTestCaseName);

	// checks the interfaces on the object, as well as count reference and parent of the rowset
	BOOL	CheckRowset(IUnknown* pIRowset);

	// @cmember GetInfo about the columns in the table
	BOOL	GetColumnInfo(DBID*, DBORDINAL*, DBCOLUMNINFO**, OLECHAR**);

	// @cmember Get an array od Column Descriptors on a Table
	BOOL	GetColumnDescOnTable(DBID*, DBCOLUMNDESC**, DBORDINAL*);

	//destructor
	virtual ~TCITableDefinition(){;}

	// @cmember Get the number of tables in a data sources, based on IDBSchemaRowset
	ULONG GetNoOfTables();
	
	//---------------------------------------------------------------------------
	// Insert				|
	// Inserts 1 row in table using IRowsetChange.
	//
	// @mfunc	Insert
	// @rdesc HRESULT indicating success or failure
	// 	@flag S_OK		| Function ran without problem
	// 	@flag E_FAIL    | No Columns Marked for use or SetNewData failed
	//
	//---------------------------------------------------------------------------
	HRESULT Insert(			
		DBCOUNTITEM		ulRowNumber,		// @parm [IN]	Row number to insert	(0 for next)		
		IUnknown		*pIUnknown,			// @parm [IN]	Pointer to rowset interface
		ULONG			cNulls = 0,			// @parm [IN]	Number of columns to be set to NULL
		DBORDINAL		*rgNulls = NULL,	// @parm [IN]	Array of columns to be set to NULL
		CTable			*pTable = NULL		// @parm [IN]	Table (DEFAULT NULL - use m_pTable)
	);

	// creates a table with not nullable column
	HRESULT	CreateTableWithNoNullableColumns(	
		CTable		*pTable,					// @param [IN] pointer to CTable 
		DBCOUNTITEM ulRowCount,					// @parm [IN] # of Rows to insert into table, 1 based
		DBORDINAL	ulIndex = 0,				// @parm [IN] Column Number of index, 1 based (Default=1)
		WCHAR		*pwszTableName = NULL,		// @parm [IN] TableName, if NULL call MakeTableName() (Default=NULL)
		EVALUE		eValue = PRIMARY,			// @parm [IN] Insert PRIMARY or SECONDARY data (Default=PRIMARY)
		BOOL		fFirstUpdateable = FALSE	// @parm [IN] TRUE means first column will be autoinc (Default=FALSE)
	);

	// @member Create the table using ITableDefinition::CreateTable and check its creation
	virtual HRESULT	CreateAndCheckTable(
		ITableDefinition	*pITableDefinition,	// [in] pointer to the ITableDefinition interface to be used
		IUnknown			*pUnkOuter,			// [in] pointer to controlling unknown
		DBID				*pTableID,			// [in]	pointer to the input table ID
		DBORDINAL			cColumnDescs,		// [in]	the number of columns to be created
		DBCOLUMNDESC		*rgColumnDescs,		// [in/out] array of columns to be created
		REFIID				riid,				// [in] rowset interface to be returned
		ULONG				cPropertySets,		// [in] number of roset property sets asked
		DBPROPSET			*rgPropertySets,	// [in/out] array of rowset property sets
		DBID				**ppTableID,		// [out] returned table ID
		IUnknown			**ppRowset			// [out] pointer to outer interface
	);

	// @member Create the table using ITableDefinitionWithConstraints::CreateTableWithConstraints and check its creation
	HRESULT			CreateAndCheckTableWithConstraints(
		ITableDefinitionWithConstraints		*pITableDefinitionWithConstraints,	// [in] pointer to the ITableDefinitionWithConstraints interface to be used
		IUnknown							*pUnkOuter,			// [in] pointer to controlling unknown
		DBID								*pTableID,			// [in]	pointer to the input table ID
		DBORDINAL							cColumnDescs,		// [in]	the number of columns to be created
		DBCOLUMNDESC						*rgColumnDescs,		// [in/out] array of columns to be created
		ULONG								cConstraintDescs,	// [in]	the number of constraints to be created
		DBCONSTRAINTDESC					*rgConstraintDescs,	// [in/out] array of constraints
		REFIID								riid,				// [in] rowset interface to be returned
		ULONG								cPropertySets,		// [in] number of roset property sets asked
		DBPROPSET							*rgPropertySets,	// [in/out] array of rowset property sets
		DBID								**ppTableID,		// [out] returned table ID
		IUnknown							**ppRowset			// [out] pointer to outer interface
	);

	// @cmember Set a property in the property sets of a DBCOLUMNDESC
	BOOL	SetProperty(
				DBPROPSET		**prgPropertySets,						// [in/out]		array of property sets
				ULONG			*pcPropertySets,						// [in/out]		number of property sets
				DBPROPID		propID,									// [in]			property ID
				DBTYPE			wType,									// [in]			value type
				LPVOID			value,									// [in]			property value
				DBPROPOPTIONS	dwOption = DBPROPOPTIONS_OPTIONAL,		// [in]			prop options
				DBID			colid = DB_NULLID,						// [in]			col id
				GUID			guidPropertySet = DBPROPSET_COLUMN,		// [in]			the GUID of the propset
				ULONG			*pcPropSet = NULL,						// [out]		index of property set 
				ULONG			*pcProp =NULL							// [out]		index in the rgProperties array
	);

};


class CLimitTable {

	IDBSchemaRowset								*m_pIDBSchemaRowset;
	ITableDefinitionWithConstraints				*m_pITDWC;
	DBCOUNTITEM									m_IndexColSize,
												m_IndexNullable,
												m_IndexLong,
												m_IndexFixedLength,
												m_IndexDataType,
												m_IndexTypeName;

	// Selected column specs
	DBLENGTH									m_cSelectedColSize;
	DBTYPE										m_dbtSelectedCol;
	WCHAR										*m_pwszSelectedCol;

	HRESULT			Init();
	
	HRESULT			GetBestType();
	HRESULT			FindIndexes(IRowset *pIRowset);
	HRESULT			CreateTable(DBCOUNTITEM cTotalCol, DBID **ppTableID);

	HRESULT			CreatePrimaryKey(DBID *pTableID, DBCOUNTITEM cTotalCols);
	HRESULT			CreateUniqueKey(DBID *pTableID, DBCOUNTITEM cTotalCols);
	HRESULT			CreateForeignKey(DBID *pBaseID, DBID *pRefID, DBCOUNTITEM cTotalCols);

public:
	CLimitTable();
	~CLimitTable();

	HRESULT		CheckPrimaryKeyLimit();
	HRESULT		CheckUniqueKeyLimit();
	HRESULT		CheckForeignKeyLimit();

	HRESULT		DropTable(DBID *pTableID);
};


CLimitTable::CLimitTable() {
	m_pIDBSchemaRowset				=		NULL;
	m_pITDWC						=		NULL;

	m_IndexColSize					=		-1;
	m_IndexNullable					=		-1;
	m_IndexLong						=		-1;
	m_IndexFixedLength				=		-1;
	m_IndexDataType					=		-1;
	m_IndexTypeName					=		-1;

	m_cSelectedColSize				=		ULONG_MAX;
	m_dbtSelectedCol				=		-1;
	m_pwszSelectedCol				=		NULL;
}

CLimitTable::~CLimitTable() {
	PROVIDER_FREE(m_pwszSelectedCol);

	SAFE_RELEASE(m_pITDWC);
	SAFE_RELEASE(m_pIDBSchemaRowset);
}

HRESULT	CLimitTable::Init() {
	TBEGIN

	ULONG				ulTotalSchemas					=	0,
						i;
	GUID				*rgSchemas						=	NULL;
	ULONG				*rgRestrictions					=	NULL;
	bool				fResult							=	false;

	// init varaibles
	m_IndexColSize					=		-1;
	m_IndexNullable					=		-1;
	m_IndexLong						=		-1;
	m_IndexFixedLength				=		-1;
	m_IndexDataType					=		-1;
	m_IndexTypeName					=		-1;

	m_cSelectedColSize				=		ULONG_MAX;
	m_dbtSelectedCol				=		-1;

	PROVIDER_FREE(m_pwszSelectedCol);

	SAFE_RELEASE(m_pITDWC);
	SAFE_RELEASE(m_pIDBSchemaRowset);

	// Verify that IDBSchemaRowset is supported
	TESTC_PROVIDER(VerifyInterface(GetModInfo()->GetThisTestModule()->m_pIUnknown2, IID_IDBSchemaRowset,
				SESSION_INTERFACE, (IUnknown**) &m_pIDBSchemaRowset));

	// Verify that ITableDefinitionWithConstraints is supported
	TESTC_PROVIDER(VerifyInterface(GetModInfo()->GetThisTestModule()->m_pIUnknown2, IID_ITableDefinitionWithConstraints,
				SESSION_INTERFACE, (IUnknown**) &m_pITDWC));

	// Now check if DBSCHEMA_PROVIDER_TYPES is supported
	TESTC_(m_pIDBSchemaRowset->GetSchemas(&ulTotalSchemas, &rgSchemas, &rgRestrictions), S_OK);

	fResult		=	false;
	for(i = 0; i < ulTotalSchemas; i++)
		if (rgSchemas[i]	==	DBSCHEMA_PROVIDER_TYPES)
			fResult	= true;
	TESTC(fResult);

CLEANUP:
	PROVIDER_FREE(rgSchemas);
	PROVIDER_FREE(rgRestrictions);

	TRETURN
}


HRESULT	CLimitTable::FindIndexes(IRowset *pIRowset) {
	TBEGIN

	IColumnsInfo		*pIColInfo		=	NULL;
	DBORDINAL			cTotalCols		=	0;
	DBCOLUMNINFO		*rgColInfo		=	NULL;
	OLECHAR				*pwszBuffer		=	NULL;
	ULONG				i;

	TESTC(pIRowset!=NULL);
	TESTC_(pIRowset->QueryInterface(IID_IColumnsInfo, (void**) &pIColInfo), S_OK);
	TESTC_(pIColInfo->GetColumnInfo(&cTotalCols, &rgColInfo, &pwszBuffer), S_OK);

	for(i=0;i<cTotalCols;i++) {
		if (!wcscmp(rgColInfo[i].pwszName, L"COLUMN_SIZE"))
			m_IndexColSize = i;
		else if (!wcscmp(rgColInfo[i].pwszName, L"IS_NULLABLE"))
			m_IndexNullable = i;
		else if (!wcscmp(rgColInfo[i].pwszName, L"IS_LONG"))
			m_IndexLong = i;
		else if (!wcscmp(rgColInfo[i].pwszName, L"IS_FIXEDLENGTH"))
			m_IndexFixedLength = i;
		else if (!wcscmp(rgColInfo[i].pwszName, L"DATA_TYPE"))
			m_IndexDataType = i;
		else if (!wcscmp(rgColInfo[i].pwszName, L"TYPE_NAME"))
			m_IndexTypeName = i;
	}

	TESTC(m_IndexColSize!=-1 && m_IndexNullable!=-1 && m_IndexLong!=-1 && m_IndexFixedLength!=-1 &&
		m_IndexDataType!=-1 && m_IndexTypeName!=-1);

CLEANUP:
	PROVIDER_FREE(pwszBuffer);
	PROVIDER_FREE(rgColInfo);
	SAFE_RELEASE(pIColInfo);

	TRETURN
}

HRESULT	CLimitTable::GetBestType() {
	TBEGIN
	IRowset					*pIRowset			=	NULL;
	IAccessor				*pIAccessor			=	NULL;
	HACCESSOR				hAccessor			=	NULL;
	DBBINDING				*rgBindings			=	NULL;
	DBCOUNTITEM				cBindings			=	0,
							cRowSize			=	0;
	HROW					*phRows				=	NULL;
	DBCOUNTITEM				cRowsObtained		=	0;
	char					*pszRowData			=	NULL;
	bool					fResult				=	false,
							IsSQLServer7		=	false;
	WCHAR					*pwszVer			=	NULL;
	CLSID					clsidSQL;

	TESTC(m_pIDBSchemaRowset && m_pITDWC);

	// Hack for SQL Server 7.0 which doesnt allow keys on BIT data type but provides
	// no way to determine this behavior.
	TESTC_(CLSIDFromProgID(L"SQLOLEDB", &clsidSQL), S_OK);

	if (PROVIDER_CLSID == clsidSQL) {
		if (::SupportedProperty(DBPROP_DBMSVER, DBPROPSET_DATASOURCEINFO, 
			GetModInfo()->GetThisTestModule()->m_pIUnknown)) {

			TESTC(::GetProperty(DBPROP_DBMSVER, DBPROPSET_DATASOURCEINFO,
				GetModInfo()->GetThisTestModule()->m_pIUnknown, 
				&pwszVer));

			if (wcscmp(pwszVer, L"08.00.0000")<0)
				IsSQLServer7	=	true;
		}

	}

	// Get provider types rowset
	TESTC_(m_pIDBSchemaRowset->GetRowset(NULL, DBSCHEMA_PROVIDER_TYPES, 0, NULL,
		IID_IRowset, 0, NULL, (IUnknown**) &pIRowset), S_OK);

	// find indexes to different columns
	TESTC(FindIndexes(pIRowset));

	// get accessor
	TESTC(VerifyInterface(pIRowset, IID_IAccessor, ROWSET_INTERFACE, (IUnknown**)&pIAccessor));

	// Create accessor
	TESTC_(GetAccessorAndBindings(pIRowset, DBACCESSOR_ROWDATA, &hAccessor,
		&rgBindings, &cBindings, &cRowSize, DBPART_VALUE | DBPART_STATUS | DBPART_LENGTH,
		ALL_COLS_BOUND, FORWARD, NO_COLS_BY_REF, NULL, NULL,
		NULL, DBTYPE_EMPTY, 0, NULL), S_OK);

	// Now get data and find best matching row
	pszRowData		=	(char*) PROVIDER_ALLOC(cRowSize);
	fResult			=	false;

	while(pIRowset->GetNextRows(DB_NULL_HCHAPTER, 0, 1, &cRowsObtained, &phRows)==S_OK) {
		pIRowset->GetData(phRows[0], hAccessor, pszRowData);

		if (*(VARIANT_BOOL*)&pszRowData[rgBindings[m_IndexNullable].obValue] == VARIANT_TRUE &&
			*(VARIANT_BOOL*)&pszRowData[rgBindings[m_IndexLong].obValue] == VARIANT_FALSE &&
			*(VARIANT_BOOL*)&pszRowData[rgBindings[m_IndexFixedLength].obValue] == VARIANT_TRUE &&
			
			!(IsSQLServer7 && !wcscmp((WCHAR*)&pszRowData[rgBindings[m_IndexTypeName].obValue], L"bit"))
			) {

			if (*(DWORD*)&pszRowData[rgBindings[m_IndexColSize].obValue] < m_cSelectedColSize) {

				m_cSelectedColSize		= *(DWORD*)&pszRowData[rgBindings[m_IndexColSize].obValue];
				m_dbtSelectedCol		= *(WORD*) &pszRowData[rgBindings[m_IndexDataType].obValue];
				PROVIDER_FREE(m_pwszSelectedCol);
				m_pwszSelectedCol		= wcsDuplicate((WCHAR*) &pszRowData[rgBindings[m_IndexTypeName].obValue]);
				fResult			= true;
			}
		}

		TESTC_(pIRowset->ReleaseRows(1, phRows, NULL, NULL, NULL), S_OK)
		PROVIDER_FREE(phRows);
		cRowsObtained	=	0;
	}

	TESTC(fResult);
	
	odtLog << "Using '" << m_pwszSelectedCol << "' data type to find maximum limit\n";

CLEANUP:
	PROVIDER_FREE(rgBindings);
	PROVIDER_FREE(pszRowData);
	PROVIDER_FREE(pwszVer);
	if (hAccessor && pIAccessor)
		pIAccessor->ReleaseAccessor(hAccessor, NULL);

	SAFE_RELEASE(pIAccessor);
	SAFE_RELEASE(pIRowset);

	TRETURN
}

HRESULT	CLimitTable::CreateTable(DBCOUNTITEM cTotalCol, DBID **ppTableID) {
	TBEGIN

	DBCOLUMNDESC		*rgColDesc				=	NULL;
	DBCOUNTITEM			i;
	WCHAR				*pwszColName			=	NULL;
	IRowset				*pIRowset				=	NULL;
	DBID				*pid					=	NULL;
	DBPROPSET			PropSet;
	DBPROP				Prop;

	rgColDesc		=	(DBCOLUMNDESC*) PROVIDER_ALLOC(cTotalCol * sizeof(DBCOLUMNDESC));
	pwszColName		=	(WCHAR*) PROVIDER_ALLOC(1024);

	Prop.dwPropertyID		=	DBPROP_COL_NULLABLE;
	Prop.dwOptions			=	DBPROPOPTIONS_REQUIRED;
	Prop.dwStatus			=	DBPROPSTATUS_OK;
	Prop.colid				=	DB_NULLID;
	VariantInit(&Prop.vValue);
	V_VT(&Prop.vValue)		=	VT_BOOL;
	V_BOOL(&Prop.vValue)	=	VARIANT_FALSE;

	PropSet.guidPropertySet	=	DBPROPSET_COLUMN;
	PropSet.cProperties		=	1;
	PropSet.rgProperties	=	&Prop;

	// Create Column Description structure
	for (i=0; i<cTotalCol; i++) {
		swprintf(pwszColName, L"Col%d", i);
		rgColDesc[i].pwszTypeName		=	m_pwszSelectedCol;
		rgColDesc[i].pTypeInfo			=	NULL;
		rgColDesc[i].rgPropertySets		=	&PropSet;	//NULL;
		rgColDesc[i].pclsid				=	NULL;
		rgColDesc[i].cPropertySets		=	1;			//0;
		rgColDesc[i].ulColumnSize		=	m_cSelectedColSize;
		rgColDesc[i].dbcid.eKind		=	DBKIND_NAME;
		rgColDesc[i].dbcid.uName.pwszName = wcsDuplicate(pwszColName);
		rgColDesc[i].bPrecision			=	0;
		rgColDesc[i].bScale				=	0;
	}


	// Now create table
	TESTC_(m_pITDWC->CreateTable(NULL, NULL, cTotalCol,
				rgColDesc, IID_IRowset, 0, NULL,
				&pid, (IUnknown**) &pIRowset), S_OK);

	*ppTableID = pid;
	for(i=0;i < cTotalCol; i++)
		PROVIDER_FREE(rgColDesc[i].dbcid.uName.pwszName);

CLEANUP:
	PROVIDER_FREE(pwszColName);
	PROVIDER_FREE(rgColDesc);
	
	SAFE_RELEASE(pIRowset);

	TRETURN
}

HRESULT	CLimitTable::CreatePrimaryKey(DBID *pTableID, DBCOUNTITEM cTotalCols) {

	DBID				*pPKDBID		=	NULL;
	DBCOUNTITEM			i;
	WCHAR				*pwszColName	=	NULL;
	HRESULT				hr				=	E_FAIL;
	DBCONSTRAINTDESC	Cons;
	DBID				ConsID;

	ASSERT(pTableID && cTotalCols > 0);
	pwszColName		=	(WCHAR*) PROVIDER_ALLOC(1024);

	// Build PK columns list
	pPKDBID		=	(DBID*) PROVIDER_ALLOC(sizeof(DBID) * cTotalCols);
	for(i=0; i<cTotalCols; i++) {
		swprintf(pwszColName, L"Col%d", i);
		pPKDBID[i].eKind				=	DBKIND_NAME;
		pPKDBID[i].uName.pwszName		=	wcsDuplicate(pwszColName);
	}

	// Build constraint DBID
	ConsID.eKind				=	DBKIND_NAME;
	ConsID.uName.pwszName		=	L"PKConstraint";

	// Build constraint structure
	Cons.pConstraintID				=	&ConsID;
	Cons.ConstraintType				=	DBCONSTRAINTTYPE_PRIMARYKEY;
	Cons.cColumns					=	cTotalCols;
	Cons.rgColumnList				=	pPKDBID;
	Cons.pReferencedTableID			=	NULL;
	Cons.cForeignKeyColumns			=	0;
	Cons.rgForeignKeyColumnList		=	NULL;
	Cons.pwszConstraintText			=	NULL;
	Cons.cReserved					=	0;
	Cons.rgReserved					=	NULL;
	Cons.Deferrability				=	0;

	hr		=	m_pITDWC->AddConstraint(pTableID, &Cons);

	for(i=0; i<cTotalCols; i++)
		PROVIDER_FREE(pPKDBID[i].uName.pwszName);
	PROVIDER_FREE(pPKDBID);
	PROVIDER_FREE(pwszColName);

	return hr;
}

HRESULT	CLimitTable::CreateUniqueKey(DBID *pTableID, DBCOUNTITEM cTotalCols) {

	DBID				*pPKDBID		=	NULL;
	DBCOUNTITEM			i;
	WCHAR				*pwszColName	=	NULL;
	HRESULT				hr				=	E_FAIL;
	DBCONSTRAINTDESC	Cons;
	DBID				ConsID;

	ASSERT(pTableID && cTotalCols > 0);
	pwszColName		=	(WCHAR*) PROVIDER_ALLOC(1024);

	// Build PK columns list
	pPKDBID		=	(DBID*) PROVIDER_ALLOC(sizeof(DBID) * cTotalCols);
	for(i=0; i<cTotalCols; i++) {
		swprintf(pwszColName, L"Col%d", i);
		pPKDBID[i].eKind				=	DBKIND_NAME;
		pPKDBID[i].uName.pwszName		=	wcsDuplicate(pwszColName);
	}

	// Build constraint DBID
	ConsID.eKind				=	DBKIND_NAME;
	ConsID.uName.pwszName		=	L"UniqueConstraint";

	// Build constraint structure
	Cons.pConstraintID				=	&ConsID;
	Cons.ConstraintType				=	DBCONSTRAINTTYPE_UNIQUE;
	Cons.cColumns					=	cTotalCols;
	Cons.rgColumnList				=	pPKDBID;
	Cons.pReferencedTableID			=	NULL;
	Cons.cForeignKeyColumns			=	0;
	Cons.rgForeignKeyColumnList		=	NULL;
	Cons.pwszConstraintText			=	NULL;
	Cons.cReserved					=	0;
	Cons.rgReserved					=	NULL;
	Cons.Deferrability				=	0;

	hr		=	m_pITDWC->AddConstraint(pTableID, &Cons);

	for(i=0; i<cTotalCols; i++)
		PROVIDER_FREE(pPKDBID[i].uName.pwszName);
	PROVIDER_FREE(pPKDBID);
	PROVIDER_FREE(pwszColName);

	return hr;
}

HRESULT	CLimitTable::CreateForeignKey(DBID *pBaseID, DBID *pRefID, DBCOUNTITEM cTotalCols) {
	DBID				*pPKDBID		=	NULL,
						*pFKDBID		=	NULL;
	DBCOUNTITEM			i;
	WCHAR				*pwszColName	=	NULL;
	HRESULT				hr				=	E_FAIL;
	DBCONSTRAINTDESC	Cons;
	DBID				ConsID;

	ASSERT(pBaseID && pRefID && cTotalCols > 0);
	pwszColName		=	(WCHAR*) PROVIDER_ALLOC(1024);

	// Build PK columns list
	pPKDBID		=	(DBID*) PROVIDER_ALLOC(sizeof(DBID) * cTotalCols);
	for(i=0; i<cTotalCols; i++) {
		swprintf(pwszColName, L"Col%d", i);
		pPKDBID[i].eKind				=	DBKIND_NAME;
		pPKDBID[i].uName.pwszName		=	wcsDuplicate(pwszColName);
	}

	// Build FK columns list
	pFKDBID		=	(DBID*) PROVIDER_ALLOC(sizeof(DBID) * cTotalCols);
	for(i=0; i<cTotalCols; i++) {
		swprintf(pwszColName, L"Col%d", i);
		pFKDBID[i].eKind				=	DBKIND_NAME;
		pFKDBID[i].uName.pwszName		=	wcsDuplicate(pwszColName);
	}


	// Build constraint DBID
	ConsID.eKind				=	DBKIND_NAME;
	ConsID.uName.pwszName		=	L"FKConstraint";

	// Build constraint structure
	Cons.pConstraintID				=	&ConsID;
	Cons.ConstraintType				=	DBCONSTRAINTTYPE_FOREIGNKEY;
	Cons.cColumns					=	cTotalCols;
	Cons.rgColumnList				=	pPKDBID;
	Cons.pReferencedTableID			=	pRefID;
	Cons.cForeignKeyColumns			=	cTotalCols;
	Cons.rgForeignKeyColumnList		=	pFKDBID;
	Cons.pwszConstraintText			=	NULL;
	Cons.cReserved					=	0;
	Cons.rgReserved					=	NULL;
	Cons.Deferrability				=	0;
	Cons.UpdateRule					=	DBUPDELRULE_NOACTION;
	Cons.DeleteRule					=	DBUPDELRULE_NOACTION;
	Cons.MatchType					=	DBMATCHTYPE_NONE;

	TESTC_(hr		=	m_pITDWC->AddConstraint(pBaseID, &Cons), S_OK);

	for(i=0; i<cTotalCols; i++) {
		PROVIDER_FREE(pPKDBID[i].uName.pwszName);
		PROVIDER_FREE(pFKDBID[i].uName.pwszName);
	}

	PROVIDER_FREE(pPKDBID);
	PROVIDER_FREE(pFKDBID);

	PROVIDER_FREE(pwszColName);
CLEANUP:
	return hr;
}



HRESULT CLimitTable::CheckPrimaryKeyLimit() {
	TBEGIN

	DBID		*pTableID		=	NULL;
	DBCOUNTITEM	i				=	0;
	HRESULT		hr				=	S_OK;
	// Initialize everything
	TESTC(Init());

	// Get provider types to be used in testing
	TESTC(GetBestType());

	// find the limit
	for(i = 1; i <= 256; i++) {
		TESTC(CreateTable(i, &pTableID));
		hr	=	CreatePrimaryKey(pTableID, i);
		TESTC(DropTable(pTableID));

		if (FAILED(hr)) {
			hr	=	S_OK;
			break;
		}
	}

	i--;
	odtLog << "Maximum columns in Primary Key allowed: " << i << "\n";
	TESTC(i != 0);

CLEANUP:
	return hr;
}


HRESULT CLimitTable::CheckUniqueKeyLimit() {
	TBEGIN

	DBID		*pTableID		=	NULL;
	DBCOUNTITEM	i				=	0;
	HRESULT		hr				=	S_OK;
	// Initialize everything
	TESTC(Init());

	// Get provider types to be used in testing
	TESTC(GetBestType());

	// find the limit
	for(i = 1; i <= 256; i++) {
		TESTC(CreateTable(i, &pTableID));
		hr	=	CreateUniqueKey(pTableID, i);
		TESTC(DropTable(pTableID));

		if (FAILED(hr)) {
			hr	=	S_OK;
			break;
		}
	}

	i--;
	odtLog << "Maximum columns in Unique Key allowed: " << i << "\n";
	TESTC(i != 0);

CLEANUP:
	return hr;
}


HRESULT CLimitTable::CheckForeignKeyLimit() {
	TBEGIN

	DBID		*pBaseID		=	NULL,
				*pRefID			=	NULL;
	DBCOUNTITEM	i				=	0;
	HRESULT		hr				=	S_OK;

	// Initialize everything
	TESTC(Init());

	// Get provider types to be used in testing
	TESTC(GetBestType());

	// find the limit
	for(i = 1; i <= 256; i++) {
		TESTC(CreateTable(i, &pBaseID));
		TESTC(CreateTable(i, &pRefID));

		hr	=	CreatePrimaryKey(pBaseID, i);
		if (SUCCEEDED(hr)) {
			hr	=	CreateUniqueKey(pRefID, i);
			if (SUCCEEDED(hr)) {
				hr	=	CreateForeignKey(pBaseID, pRefID, i);
			}
		}
		TESTC(DropTable(pBaseID));
		TESTC(DropTable(pRefID));

		PROVIDER_FREE(pBaseID);
		PROVIDER_FREE(pRefID);

		if (FAILED(hr)) {
			hr	=	S_OK;
			break;
		}
	}

	i--;
	odtLog << "Maximum columns in Foreign Key allowed: " << i << "\n";
	TESTC(i != 0);

CLEANUP:
	return hr;
}

HRESULT CLimitTable::DropTable(DBID *pTableID)
{
	TBEGIN
	
	TESTC(m_pITDWC != NULL);
	TESTC_(m_pITDWC->DropTable(pTableID), S_OK);

CLEANUP:
	TRETURN
}


// {{ TCW_TEST_CASE_MAP(TCAddColumn)
//--------------------------------------------------------------------
// @class Testcase for ITableDefinition::AddColumn
//
class TCAddColumn : public TCITableDefinition { 
private:
	// @cmember Static array of variations
	DECLARE_TEST_CASE_DATA();

public:
	// {{ TCW_DECLARE_FUNCS
	// @cmember Execution Routine
	DECLARE_TEST_CASE_FUNCS(TCAddColumn,TCITableDefinition);
	// }} TCW_DECLARE_FUNCS_END
 
	// @cmember Initialization Routine
	virtual BOOL Init();
	// @cmember Termination Routine
	virtual BOOL Terminate();
	
	// {{ TCW_TESTVARS()
	// @cmember Table doesn't exist => DB_E_NOTABLE
	int Variation_1();
	// @cmember The table is in use => DB_E_TABLEINUSE
	int Variation_2();
	// @cmember *pTableID = DB_NULLID => DB_E_NOTABLE
	int Variation_3();
	// @cmember pTableID = NULL => E_INVALIDARG
	int Variation_4();
	// @cmember Maximum length for table name => S_OK
	int Variation_5();
	// @cmember the table name is 1 char too long => DB_E_NOTABLE
	int Variation_6();
	// @cmember invalid table name => DB_E_NOTABLE
	int Variation_7();
	// @cmember pColumnDesc->dbcid = DB_NULLID
	int Variation_8();
	// @cmember Column name pointer is NULL => DB_E_BADCOLUMNID
	int Variation_9();
	// @cmember column name is an empty string => DB_E_BADCOLUMNID
	int Variation_10();
	// @cmember Maximum length of column name => S_OK
	int Variation_11();
	// @cmember 1-char-too-long column name => DB_E_BADCOLUMNID
	int Variation_12();
	// @cmember Add a column for each provider type, maximum column size => S_OK
	int Variation_13();
	// @cmember Add a column for each known type; ulColumnsize == 0 => S_OK
	int Variation_14();
	// @cmember Add a column for each provider type (table is populated) => S_OK
	int Variation_15();
	// @cmember Precision testing
	int Variation_16();
	// @cmember Scale testing
	int Variation_17();
	// @cmember Invalid value for the property of a column => DB_E_ERRORSOCCURRED
	int Variation_18();
	// @cmember Non-column property => DBPROPSTATUS_NOTSUPPORTED
	int Variation_19();
	// @cmember Inexistent property => DBPROPSTATUS_NOTSUPPORTED
	int Variation_20();
	// @cmember Bad option => DBPROPSTATUS_BADOPTION
	int Variation_21();
	// @cmember Conflicting property => DBPROPSTATUS_CONFLICTING
	int Variation_22();
	// @cmember Bad column ID for a property => ignored
	int Variation_23();
	// @cmember Bad column type (wType in DBCOLUMNDESC)
	int Variation_24();
	// @cmember Invalid provider type name for a column => DB_E_BADTYPE
	int Variation_25();
	// @cmember NULL ppColumnDesc => S_OK
	int Variation_26();
	// @cmember Autoincrementable column - DBPROP_COL_AUTOINCREMENT
	int Variation_27();
	// @cmember DBPROP_COL_DEFAULT
	int Variation_28();
	// @cmember DBPROP_COL_DESCRIPTION
	int Variation_29();
	// @cmember DBPROP_COL_FIXEDLENGTH
	int Variation_30();
	// @cmember DBPROP_COL_NULLABLE
	int Variation_31();
	// @cmember DBPROP_PRIMARYKEY
	int Variation_32();
	// @cmember DBPROP_COL_UNIQUE
	int Variation_33();
	// @cmember Duplicate an existing column => DB_E_DUPLCATECOLUMNID
	int Variation_34();
	// @cmember Abort retaining
	int Variation_35();
	// @cmember Abort without retaining
	int Variation_36();
	// @cmember Commit with retain
	int Variation_37();
	// @cmember Commit without retain
	int Variation_38();
	// @cmember Add a column for each provider type in an empty table => S_OK
	int Variation_39();
	// @cmember Add a column to a table created with a SQL command => S_OK
	int Variation_40();
	// @cmember Drop all the column of a table (via SQL stmt) and then try to add a column => S_OK
	int Variation_41();
	// @cmember Non NULL pTypeInfo in DBCOLUMNDESC => DB_E_BADTYPE
	int Variation_42();
	// @cmember Missmatch between wType and pwszTypeName => DB_E_BADTYPE
	int Variation_43();
	// @cmember Add a not nullable column and try to insert a null value for it
	int Variation_44();
	// @cmember Add a column on a view
	int Variation_45();
	// @cmember eKind != DBKIND_NAME for a column
	int Variation_46();
	// @cmember threads with different column
	int Variation_47();
	// @cmember threads on the same column
	int Variation_48();
	// @cmember add columns of alll known wType => S_OK
	int Variation_49();
	// @cmember Fully Qualified table name
	int Variation_50();
	// @cmember Quoted Table Name
	int Variation_51();
	// @cmember pColumnDesc == NULL => E_INVALIDARG
	int Variation_52();
	// @cmember cPropertySets != 0 and rgPropertySets == NULL in pColumnDesc => E_INVALIDARG
	int Variation_53();
	// @cmember cPropertySets == 0 and rgPropertySets != NULL in pColumnDesc => S_OK
	int Variation_54();
	// @cmember cProperties == 0 and rgProperties != NULL in pColumnDesc's propset => S_OK
	int Variation_55();
	// @cmember cProperties != 0 and rgProperties == NULL in pColumnDesc's propset => E_INVALIDARG
	int Variation_56();
	// @cmember pclsid not null
	int Variation_57();
	// @cmember NULL pwszTypeName => S_OK
	int Variation_58();
	// }} TCW_TESTVARS_END

	unsigned MyThreadProc(ULONG i);
};
// {{ TCW_TESTCASE(TCAddColumn)
#define THE_CLASS TCAddColumn
BEG_TEST_CASE(TCAddColumn, TCITableDefinition, L"Testcase for ITableDefinition::AddColumn")
	TEST_VARIATION(1, 		L"Table doesn't exist => DB_E_NOTABLE")
	TEST_VARIATION(2, 		L"The table is in use => DB_E_TABLEINUSE")
	TEST_VARIATION(3, 		L"*pTableID = DB_NULLID => DB_E_NOTABLE")
	TEST_VARIATION(4, 		L"pTableID = NULL => E_INVALIDARG")
	TEST_VARIATION(5, 		L"Maximum length for table name => S_OK")
	TEST_VARIATION(6, 		L"the table name is 1 char too long => DB_E_NOTABLE")
	TEST_VARIATION(7, 		L"invalid table name => DB_E_NOTABLE")
	TEST_VARIATION(8, 		L"pColumnDesc->dbcid = DB_NULLID")
	TEST_VARIATION(9, 		L"Column name pointer is NULL => DB_E_BADCOLUMNID")
	TEST_VARIATION(10, 		L"column name is an empty string => DB_E_BADCOLUMNID")
	TEST_VARIATION(11, 		L"Maximum length of column name => S_OK")
	TEST_VARIATION(12, 		L"1-char-too-long column name => DB_E_BADCOLUMNID")
	TEST_VARIATION(13, 		L"Add a column for each provider type, maximum column size => S_OK")
	TEST_VARIATION(14, 		L"Add a column for each known type; ulColumnsize == 0 => S_OK")
	TEST_VARIATION(15, 		L"Add a column for each provider type (table is populated) => S_OK")
	TEST_VARIATION(16, 		L"Precision testing")
	TEST_VARIATION(17, 		L"Scale testing")
	TEST_VARIATION(18, 		L"Invalid value for the property of a column => DB_E_ERRORSOCCURRED")
	TEST_VARIATION(19, 		L"Non-column property => DBPROPSTATUS_NOTSUPPORTED")
	TEST_VARIATION(20, 		L"Inexistent property => DBPROPSTATUS_NOTSUPPORTED")
	TEST_VARIATION(21, 		L"Bad option => DBPROPSTATUS_BADOPTION")
	TEST_VARIATION(22, 		L"Conflicting property => DBPROPSTATUS_CONFLICTING")
	TEST_VARIATION(23, 		L"Bad column ID for a property => ignored")
	TEST_VARIATION(24, 		L"Bad column type (wType in DBCOLUMNDESC)")
	TEST_VARIATION(25, 		L"Invalid provider type name for a column => DB_E_BADTYPE")
	TEST_VARIATION(26, 		L"NULL ppColumnDesc => S_OK")
	TEST_VARIATION(27, 		L"Autoincrementable column - DBPROP_COL_AUTOINCREMENT")
	TEST_VARIATION(28, 		L"DBPROP_COL_DEFAULT")
	TEST_VARIATION(29, 		L"DBPROP_COL_DESCRIPTION")
	TEST_VARIATION(30, 		L"DBPROP_COL_FIXEDLENGTH")
	TEST_VARIATION(31, 		L"DBPROP_COL_NULLABLE")
	TEST_VARIATION(32, 		L"DBPROP_PRIMARYKEY")
	TEST_VARIATION(33, 		L"DBPROP_COL_UNIQUE")
	TEST_VARIATION(34, 		L"Duplicate an existing column => DB_E_DUPLCATECOLUMNID")
	TEST_VARIATION(35, 		L"Abort retaining")
	TEST_VARIATION(36, 		L"Abort without retaining")
	TEST_VARIATION(37, 		L"Commit with retain")
	TEST_VARIATION(38, 		L"Commit without retain")
	TEST_VARIATION(39, 		L"Add a column for each provider type in an empty table => S_OK")
	TEST_VARIATION(40, 		L"Add a column to a table created with a SQL command => S_OK")
	TEST_VARIATION(41, 		L"Drop all the column of a table (via SQL stmt) and then try to add a column => S_OK")
	TEST_VARIATION(42, 		L"Non NULL pTypeInfo in DBCOLUMNDESC => DB_E_BADTYPE")
	TEST_VARIATION(43, 		L"Missmatch between wType and pwszTypeName => DB_E_BADTYPE")
	TEST_VARIATION(44, 		L"Add a not nullable column and try to insert a null value for it")
	TEST_VARIATION(45, 		L"Add a column on a view")
	TEST_VARIATION(46, 		L"eKind != DBKIND_NAME for a column")
	TEST_VARIATION(47, 		L"threads with different column")
	TEST_VARIATION(48, 		L"threads on the same column")
	TEST_VARIATION(49, 		L"add columns of alll known wType => S_OK")
	TEST_VARIATION(50, 		L"Fully Qualified table name")
	TEST_VARIATION(51, 		L"Quoted Table Name")
	TEST_VARIATION(52, 		L"pColumnDesc == NULL => E_INVALIDARG")
	TEST_VARIATION(53, 		L"cPropertySets != 0 and rgPropertySets == NULL in pColumnDesc => E_INVALIDARG")
	TEST_VARIATION(54, 		L"cPropertySets == 0 and rgPropertySets != NULL in pColumnDesc => S_OK")
	TEST_VARIATION(55, 		L"cProperties == 0 and rgProperties != NULL in pColumnDesc's propset => S_OK")
	TEST_VARIATION(56, 		L"cProperties != 0 and rgProperties == NULL in pColumnDesc's propset => E_INVALIDARG")
	TEST_VARIATION(57, 		L"pclsid not null")
	TEST_VARIATION(58, 		L"NULL pwszTypeName => S_OK")
END_TEST_CASE()
#undef THE_CLASS
// }} TCW_TESTCASE_END
// }} TCW_TEST_CASE_MAP_END


// {{ TCW_TEST_CASE_MAP(TCDropColumn)
//--------------------------------------------------------------------
// @class Test case for dropping columns
//
class TCDropColumn : public TCITableDefinition { 
private:
	// @cmember Static array of variations
	DECLARE_TEST_CASE_DATA();
	
public:
	// {{ TCW_DECLARE_FUNCS
	// @cmember Execution Routine
	DECLARE_TEST_CASE_FUNCS(TCDropColumn,TCITableDefinition);
	// }} TCW_DECLARE_FUNCS_END
 
	// @cmember Initialization Routine
	virtual BOOL Init();
	// @cmember Termination Routine
	virtual BOOL Terminate();


	// {{ TCW_TESTVARS()
	// @cmember pTableID is NULL => E_INVALIDARG
	int Variation_1();
	// @cmember pColumnID in NULL => E_INVALIDARG
	int Variation_2();
	// @cmember *pTableID is DB_NULLID => DB_E_NOTABLE
	int Variation_3();
	// @cmember *pColumnID is DB_NULLID => DB_E_NOCOLUMN
	int Variation_4();
	// @cmember Maximum length table name => S_OK
	int Variation_5();
	// @cmember 1-char-too long table name => DB_E_NOTABLE
	int Variation_6();
	// @cmember *pTableID contains a NULL table name => DB_E_NOTABLE
	int Variation_7();
	// @cmember *pTableID contains an invalid name => DB_E_NOTABLE
	int Variation_8();
	// @cmember Maximum length for a column name => S_OK
	int Variation_9();
	// @cmember 1-char-too-long column name => DB_E_NOCOLUMN
	int Variation_10();
	// @cmember *pColumnID contains a NULL column name pointer => E_INVALIDARG
	int Variation_11();
	// @cmember *pColumnID contains an invalid column name => E_INVALID ARG
	int Variation_12();
	// @cmember Drop all the columns of a table => S_OK
	int Variation_13();
	// @cmember Try to delete an inexistent column => DB_E_NOCOLUMN
	int Variation_14();
	// @cmember Table in use => DB_E_TABLEINUSE
	int Variation_15();
	// @cmember Valid name of an inexistent table => DB_E_NOTABLE
	int Variation_16();
	// @cmember Abort with retaining
	int Variation_17();
	// @cmember Abort without retaining
	int Variation_18();
	// @cmember Commit with retaining
	int Variation_19();
	// @cmember Commit without retaining
	int Variation_20();
	// @cmember threads on different columns
	int Variation_21();
	// @cmember threads on the same column
	int Variation_22();
	// @cmember Drop a column twice => DB_E_NOCOLUMN
	int Variation_23();
	// @cmember 2 TableDefinition interfaces on the same table, try to drop 2 different columns => S_OK
	int Variation_24();
	// @cmember Drop as many column as possible from a table created with a SQL statement
	int Variation_25();
	// @cmember Drop a column from a 2 column table
	int Variation_26();
	// @cmember drop a column from a 1 column table
	int Variation_27();
	// @cmember drop a column from a non empty table => S_OK
	int Variation_28();
	// @cmember drop a column from an empty table
	int Variation_29();
	// @cmember drop a nullable, an autoincrementable and a default value column
	int Variation_30();
	// @cmember try to drop a column from a view
	int Variation_31();
	// @cmember drop a column added with an alter table command => S_OK
	int Variation_32();
	// @cmember try to drop columns using different DBKIND pattern
	int Variation_33();
	// @cmember Fully Qualified Table Name
	int Variation_34();
	// @cmember Quoted Table Name
	int Variation_35();
	// }} TCW_TESTVARS_END

	unsigned MyThreadProc(ULONG i);
};
// {{ TCW_TESTCASE(TCDropColumn)
#define THE_CLASS TCDropColumn
BEG_TEST_CASE(TCDropColumn, TCITableDefinition, L"Test case for dropping columns")
	TEST_VARIATION(1, 		L"pTableID is NULL => E_INVALIDARG")
	TEST_VARIATION(2, 		L"pColumnID in NULL => E_INVALIDARG")
	TEST_VARIATION(3, 		L"*pTableID is DB_NULLID => DB_E_NOTABLE")
	TEST_VARIATION(4, 		L"*pColumnID is DB_NULLID => DB_E_NOCOLUMN")
	TEST_VARIATION(5, 		L"Maximum length table name => S_OK")
	TEST_VARIATION(6, 		L"1-char-too long table name => DB_E_NOTABLE")
	TEST_VARIATION(7, 		L"*pTableID contains a NULL table name => DB_E_NOTABLE")
	TEST_VARIATION(8, 		L"*pTableID contains an invalid name => DB_E_NOTABLE")
	TEST_VARIATION(9, 		L"Maximum length for a column name => S_OK")
	TEST_VARIATION(10, 		L"1-char-too-long column name => DB_E_NOCOLUMN")
	TEST_VARIATION(11, 		L"*pColumnID contains a NULL column name pointer => E_INVALIDARG")
	TEST_VARIATION(12, 		L"*pColumnID contains an invalid column name => E_INVALID ARG")
	TEST_VARIATION(13, 		L"Drop all the columns of a table => S_OK")
	TEST_VARIATION(14, 		L"Try to delete an inexistent column => DB_E_NOCOLUMN")
	TEST_VARIATION(15, 		L"Table in use => DB_E_TABLEINUSE")
	TEST_VARIATION(16, 		L"Valid name of an inexistent table => DB_E_NOTABLE")
	TEST_VARIATION(17, 		L"Abort with retaining")
	TEST_VARIATION(18, 		L"Abort without retaining")
	TEST_VARIATION(19, 		L"Commit with retaining")
	TEST_VARIATION(20, 		L"Commit without retaining")
	TEST_VARIATION(21, 		L"threads on different columns")
	TEST_VARIATION(22, 		L"threads on the same column")
	TEST_VARIATION(23, 		L"Drop a column twice => DB_E_NOCOLUMN")
	TEST_VARIATION(24, 		L"2 TableDefinition interfaces on the same table, try to drop 2 different columns => S_OK")
	TEST_VARIATION(25, 		L"Drop as many column as possible from a table created with a SQL statement")
	TEST_VARIATION(26, 		L"Drop a column from a 2 column table")
	TEST_VARIATION(27, 		L"drop a column from a 1 column table")
	TEST_VARIATION(28, 		L"drop a column from a non empty table => S_OK")
	TEST_VARIATION(29, 		L"drop a column from an empty table")
	TEST_VARIATION(30, 		L"drop a nullable, an autoincrementable and a default value column")
	TEST_VARIATION(31, 		L"try to drop a column from a view")
	TEST_VARIATION(32, 		L"drop a column added with an alter table command => S_OK")
	TEST_VARIATION(33, 		L"try to drop columns using different DBKIND pattern")
	TEST_VARIATION(34, 		L"Fully Qualified Table Name")
	TEST_VARIATION(35, 		L"Quoted Table Name")
END_TEST_CASE()
#undef THE_CLASS
// }} TCW_TESTCASE_END
// }} TCW_TEST_CASE_MAP_END


// {{ TCW_TEST_CASE_MAP(TCDropTable)
//--------------------------------------------------------------------
// @class Test Case fo dropping a table
//
class TCDropTable : public TCITableDefinition { 
private:
	// @cmember Static array of variations
	DECLARE_TEST_CASE_DATA();
	
public:
	// {{ TCW_DECLARE_FUNCS
	// @cmember Execution Routine
	DECLARE_TEST_CASE_FUNCS(TCDropTable,TCITableDefinition);
	// }} TCW_DECLARE_FUNCS_END
 
	// @cmember Initialization Routine
	virtual BOOL Init();
	// @cmember Termination Routine
	virtual BOOL Terminate();
	
	// {{ TCW_TESTVARS()
	// @cmember pTableID is NULL => E_INVALIDARG
	int Variation_1();
	// @cmember *pTableID is DB_NULLID => DB_E_NOTABLE
	int Variation_2();
	// @cmember Maximum length for table name => S_OK
	int Variation_3();
	// @cmember 1-char-too-long table name => DB_E_NOTABLE
	int Variation_4();
	// @cmember The pointer to the table name is NULL => DB_E_NOTABLE
	int Variation_5();
	// @cmember Table name is empty => DB_E_NOTABLE
	int Variation_6();
	// @cmember Invalid table name => DB_E_NOTABLE
	int Variation_7();
	// @cmember A rowset is opened on table => DB_E_TABLEINUSE
	int Variation_8();
	// @cmember Table in use => DB_E_TABLEINUSE
	int Variation_9();
	// @cmember Inexistent table => DB_E_NOTABLE
	int Variation_10();
	// @cmember Abort with retaining
	int Variation_11();
	// @cmember Abort without retaining
	int Variation_12();
	// @cmember Commit with retaining
	int Variation_13();
	// @cmember Commit without retaining
	int Variation_14();
	// @cmember Drop a table created with an SQL command => S_OK
	int Variation_15();
	// @cmember Drop a table created with ITableDefinition, no rowset created => S_OK
	int Variation_16();
	// @cmember Drop a table created with ITableDefinition, rowset released => S_OK
	int Variation_17();
	// @cmember ITableDefinition::CreateTable, insert 10 rows, release rowset, drop the table => S_OK
	int Variation_18();
	// @cmember For each provider type, create a table with a single column and then drop it => S_OK
	int Variation_19();
	// @cmember Drop a table twice => DB_E_NOTABLE
	int Variation_20();
	// @cmember threads on different tables
	int Variation_21();
	// @cmember threads on same table
	int Variation_22();
	// @cmember Fully Qualified Table Name
	int Variation_23();
	// @cmember Quoted Table Name
	int Variation_24();
	// @cmember Different DBKINDs for pTableID
	int Variation_25();
	// }} TCW_TESTVARS_END

	unsigned MyThreadProc(ULONG i);
};
// {{ TCW_TESTCASE(TCDropTable)
#define THE_CLASS TCDropTable
BEG_TEST_CASE(TCDropTable, TCITableDefinition, L"Test Case fo dropping a table")
	TEST_VARIATION(1, 		L"pTableID is NULL => E_INVALIDARG")
	TEST_VARIATION(2, 		L"*pTableID is DB_NULLID => DB_E_NOTABLE")
	TEST_VARIATION(3, 		L"Maximum length for table name => S_OK")
	TEST_VARIATION(4, 		L"1-char-too-long table name => DB_E_NOTABLE")
	TEST_VARIATION(5, 		L"The pointer to the table name is NULL => DB_E_NOTABLE")
	TEST_VARIATION(6, 		L"Table name is empty => DB_E_NOTABLE")
	TEST_VARIATION(7, 		L"Invalid table name => DB_E_NOTABLE")
	TEST_VARIATION(8, 		L"A rowset is opened on table => DB_E_TABLEINUSE")
	TEST_VARIATION(9, 		L"Table in use => DB_E_TABLEINUSE")
	TEST_VARIATION(10, 		L"Inexistent table => DB_E_NOTABLE")
	TEST_VARIATION(11, 		L"Abort with retaining")
	TEST_VARIATION(12, 		L"Abort without retaining")
	TEST_VARIATION(13, 		L"Commit with retaining")
	TEST_VARIATION(14, 		L"Commit without retaining")
	TEST_VARIATION(15, 		L"Drop a table created with an SQL command => S_OK")
	TEST_VARIATION(16, 		L"Drop a table created with ITableDefinition, no rowset created => S_OK")
	TEST_VARIATION(17, 		L"Drop a table created with ITableDefinition, rowset released => S_OK")
	TEST_VARIATION(18, 		L"ITableDefinition::CreateTable, insert 10 rows, release rowset, drop the table => S_OK")
	TEST_VARIATION(19, 		L"For each provider type, create a table with a single column and then drop it => S_OK")
	TEST_VARIATION(20, 		L"Drop a table twice => DB_E_NOTABLE")
	TEST_VARIATION(21, 		L"threads on different tables")
	TEST_VARIATION(22, 		L"threads on same table")
	TEST_VARIATION(23, 		L"Fully Qualified Table Name")
	TEST_VARIATION(24, 		L"Quoted Table Name")
	TEST_VARIATION(25, 		L"Different DBKINDs for pTableID")
END_TEST_CASE()
#undef THE_CLASS
// }} TCW_TESTCASE_END
// }} TCW_TEST_CASE_MAP_END


// {{ TCW_TEST_CASE_MAP(TCCreateTable)
//--------------------------------------------------------------------
// @class TestCase for table creation
//
class TCCreateTable : public TCITableDefinition { 
public:
	// @cmember Static array of variations
	DECLARE_TEST_CASE_DATA();

public:
	// {{ TCW_DECLARE_FUNCS
	// @cmember Execution Routine
	DECLARE_TEST_CASE_FUNCS(TCCreateTable,TCITableDefinition);
	// }} TCW_DECLARE_FUNCS_END
 
	// @cmember Initialization Routine
	virtual BOOL Init();
	// @cmember Termination Routine
	virtual BOOL Terminate();

	// {{ TCW_TESTVARS()
	// @cmember Session interfaces
	int Variation_1();
	// @cmember pTableID is NULL => S_OK
	int Variation_2();
	// @cmember ppTableID is a NULL pointer => S_OK
	int Variation_3();
	// @cmember pTableID and ppTableID both NULL => E_INVALIDARG
	int Variation_4();
	// @cmember *pTableID == DB_NULLID => DB_E_BADTABLEID
	int Variation_5();
	// @cmember cColumnDesc == 0 => E_INVALIDARG or S_OK
	int Variation_6();
	// @cmember rgColumnDesc == NULL => E_INVALIDARG
	int Variation_7();
	// @cmember cPropertySets != 0 and rgPropertySets == NULL => E_INVALIDARG
	int Variation_8();
	// @cmember cPropertySets is 0 and rgPropertySets != NULL => S_OK
	int Variation_9();
	// @cmember for a property sets, cProperties != 0 and rgProperties == NULL => E_INVALIDARG
	int Variation_10();
	// @cmember cProperties == 0 on a property set => S_OK
	int Variation_11();
	// @cmember for a column, rgPropertySets is NULL though cPropertySets != 0 => E_INVALIDARG
	int Variation_12();
	// @cmember dbcid in an element of rgColumnDesc is DB_NULLID => DB_E_BADCOLUMNID
	int Variation_13();
	// @cmember dbcid in an element of rgColumnDesc is NULL => DB_E_BADCOLUMNID
	int Variation_14();
	// @cmember not null pclsid in a DBCOLUMNDESC element
	int Variation_15();
	// @cmember empty column name => DB_E_BADCOLUMNID
	int Variation_16();
	// @cmember empty table name => DB_E_BADTABLEID
	int Variation_17();
	// @cmember Maximum length for table name => S_OK
	int Variation_18();
	// @cmember 1 char too long table name => DB_E_BADTABLEID
	int Variation_19();
	// @cmember Maximum length column name => S_OK
	int Variation_20();
	// @cmember 1 char too long column name => DB_E_BADCOLUMNID
	int Variation_21();
	// @cmember ulColumnSize 0 for a variable-length column => S_OK
	int Variation_22();
	// @cmember For each provider type create and drop a table with a single column => S_OK
	int Variation_23();
	// @cmember invalid table name => DB_E_BADTABLEID
	int Variation_24();
	// @cmember pTableID provides the name of an existing table => DB_E_DUPLICATETABLEID
	int Variation_25();
	// @cmember valid riid and NULL ppRowset => S_OK
	int Variation_26();
	// @cmember invalid column name => DB_E_BADCOLUMNID
	int Variation_27();
	// @cmember invalid type name for a column (NULL, empty or inexistent)
	int Variation_28();
	// @cmember invalid wType for a column => DB_E_BADTYPE
	int Variation_29();
	// @cmember wType and pswzTypeName mismatch in a column description => DB_E_BADTYPE
	int Variation_30();
	// @cmember not null pTypeInfo => DB_E_BADTYPE (for the time being
	int Variation_31();
	// @cmember duplicate column identifiers => DB_E_DUPLICATECOLUMNID
	int Variation_32();
	// @cmember improper eKind value in a DBID => DB_E_BADCOLUMNID
	int Variation_33();
	// @cmember invalid property value on column
	int Variation_34();
	// @cmember Invalid column precision => DB_E_BADPRECISION
	int Variation_35();
	// @cmember invalid scale on column => DB_E_BADSCALE
	int Variation_36();
	// @cmember col prop is not in the Column, Rowset or Table property group and dwOption is DBPROP_SETIFCHEAP => DB_S_ERRORSOCCURRED
	int Variation_37();
	// @cmember col prop is not in the Column, Rowset or Table property group and dwOption is DBPROP_REQUIRED => DB_E_ERRORSOCCURRED
	int Variation_38();
	// @cmember invalid propID for a column propriety
	int Variation_39();
	// @cmember colid in DBPROP of a column property is ignored
	int Variation_40();
	// @cmember Abort retaining
	int Variation_41();
	// @cmember Abort without retaining
	int Variation_42();
	// @cmember Commit retain
	int Variation_43();
	// @cmember Commit non-retaining
	int Variation_44();
	// @cmember Autoincrementable columns
	int Variation_45();
	// @cmember Default values
	int Variation_46();
	// @cmember Column descriptions
	int Variation_47();
	// @cmember Variable length columns
	int Variation_48();
	// @cmember Nullable/non nullable columns
	int Variation_49();
	// @cmember Primary key column
	int Variation_50();
	// @cmember Unique columns
	int Variation_51();
	// @cmember Test conflicting properties
	int Variation_52();
	// @cmember Create a table and ask for a rowset, setting DBPROP_ABORTPRESERVE
	int Variation_53();
	// @cmember Inserting rows after table creation, using the resulting rowset
	int Variation_54();
	// @cmember Delete rows in the created rowset
	int Variation_55();
	// @cmember Aggregation, ask for IID_IUnknown
	int Variation_56();
	// @cmember Create a table and ask for a rowset, setting DBPROP_COMMITPRESERVE
	int Variation_57();
	// @cmember Create a table and ask for a rowset, setting DBPROP_OWNINSERT
	int Variation_58();
	// @cmember Create a table and ask for a rowset, setting DBPROP_BOOKMARKS
	int Variation_59();
	// @cmember Create a table and ask for a rowset, setting DBPROP_CANHOLDROWS
	int Variation_60();
	// @cmember Create a table and ask for a rowset, setting DBPROP_MAYWRITECOLUMN
	int Variation_61();
	// @cmember Ask for a rowset mandatory/optional interface when table creation => S_OK
	int Variation_62();
	// @cmember threads on different tables
	int Variation_63();
	// @cmember threads on the same table
	int Variation_64();
	// @cmember try all interfaces on rowset that can be returned
	int Variation_65();
	// @cmember create with a table property => S_OK
	int Variation_66();
	// @cmember create a table and update a row, using the rowset interface got => S_OK
	int Variation_67();
	// @cmember Fully Qualified Table Name
	int Variation_68();
	// @cmember Quoted table name
	int Variation_69();
	// @cmember Aggregation, non IID_IUnknown
	int Variation_70();
	// @cmember Aggregation -> IRowsetInfo::GetReferencedRowset
	int Variation_71();
	// @cmember Agg session -> IRowsetInfo::GetSpecification
	int Variation_72();
	// @cmember Table -> Agg ColumnRowset, ask for non IID_IUnknown
	int Variation_73();
	// @cmember Table -> Agg ColumnRowset, ask for IID_IUnknown
	int Variation_74();
	// @cmember Table -> Agg ColumnRowset -> IRowsetInfo::GetSpecification
	int Variation_75();
	// @cmember colid is ignored in a non column specific rowset property
	int Variation_76();
	// @cmember colid is DB_NULLID in a column specific rowset property => S_OK
	int Variation_77();
	// @cmember valid, non DB_NULLID colid for a column specific rowset property
	int Variation_78();
	// @cmember invalid colid for a column specific rowset property
	int Variation_79();
	// @cmember Create a table. Retrieve a rowset on it (IRowsetInfo). Check GetSpecification()
	int Variation_80();
	// @cmember DB_NULLID is ignored for non column-related table properties
	int Variation_81();
	// @cmember Column related table property set to bad colid
	int Variation_82();
	// @cmember How many DBTYPE_I4 columns?
	int Variation_83();
	// @cmember Open a rowset with CE, call IColumnRowset with an aggregated pIUnk
	int Variation_84();
	// @cmember Different DBKINDs for pTableID
	int Variation_85();
	// @cmember Different DBKINDs for column IDs
	int Variation_86();
	// }} TCW_TESTVARS_END

	unsigned MyThreadProc(ULONG i);
};
// {{ TCW_TESTCASE(TCCreateTable)
#define THE_CLASS TCCreateTable
BEG_TEST_CASE(TCCreateTable, TCITableDefinition, L"TestCase for table creation")
	TEST_VARIATION(1, 		L"Session interfaces")
	TEST_VARIATION(2, 		L"pTableID is NULL => S_OK")
	TEST_VARIATION(3, 		L"ppTableID is a NULL pointer => S_OK")
	TEST_VARIATION(4, 		L"pTableID and ppTableID both NULL => E_INVALIDARG")
	TEST_VARIATION(5, 		L"*pTableID == DB_NULLID => DB_E_BADTABLEID")
	TEST_VARIATION(6, 		L"cColumnDesc == 0 => E_INVALIDARG or S_OK")
	TEST_VARIATION(7, 		L"rgColumnDesc == NULL => E_INVALIDARG")
	TEST_VARIATION(8, 		L"cPropertySets != 0 and rgPropertySets == NULL => E_INVALIDARG")
	TEST_VARIATION(9, 		L"cPropertySets is 0 and rgPropertySets != NULL => S_OK")
	TEST_VARIATION(10, 		L"for a property sets, cProperties != 0 and rgProperties == NULL => E_INVALIDARG")
	TEST_VARIATION(11, 		L"cProperties == 0 on a property set => S_OK")
	TEST_VARIATION(12, 		L"for a column, rgPropertySets is NULL though cPropertySets != 0 => E_INVALIDARG")
	TEST_VARIATION(13, 		L"dbcid in an element of rgColumnDesc is DB_NULLID => DB_E_BADCOLUMNID")
	TEST_VARIATION(14, 		L"dbcid in an element of rgColumnDesc is NULL => DB_E_BADCOLUMNID")
	TEST_VARIATION(15, 		L"not null pclsid in a DBCOLUMNDESC element")
	TEST_VARIATION(16, 		L"empty column name => DB_E_BADCOLUMNID")
	TEST_VARIATION(17, 		L"empty table name => DB_E_BADTABLEID")
	TEST_VARIATION(18, 		L"Maximum length for table name => S_OK")
	TEST_VARIATION(19, 		L"1 char too long table name => DB_E_BADTABLEID")
	TEST_VARIATION(20, 		L"Maximum length column name => S_OK")
	TEST_VARIATION(21, 		L"1 char too long column name => DB_E_BADCOLUMNID")
	TEST_VARIATION(22, 		L"ulColumnSize 0 for a variable-length column => S_OK")
	TEST_VARIATION(23, 		L"For each provider type create and drop a table with a single column => S_OK")
	TEST_VARIATION(24, 		L"invalid table name => DB_E_BADTABLEID")
	TEST_VARIATION(25, 		L"pTableID provides the name of an existing table => DB_E_DUPLICATETABLEID")
	TEST_VARIATION(26, 		L"valid riid and NULL ppRowset => S_OK")
	TEST_VARIATION(27, 		L"invalid column name => DB_E_BADCOLUMNID")
	TEST_VARIATION(28, 		L"invalid type name for a column (NULL, empty or inexistent)")
	TEST_VARIATION(29, 		L"invalid wType for a column => DB_E_BADTYPE")
	TEST_VARIATION(30, 		L"wType and pswzTypeName mismatch in a column description => DB_E_BADTYPE")
	TEST_VARIATION(31, 		L"not null pTypeInfo => DB_E_BADTYPE (for the time being")
	TEST_VARIATION(32, 		L"duplicate column identifiers => DB_E_DUPLICATECOLUMNID")
	TEST_VARIATION(33, 		L"improper eKind value in a DBID => DB_E_BADCOLUMNID")
	TEST_VARIATION(34, 		L"invalid property value on column")
	TEST_VARIATION(35, 		L"Invalid column precision => DB_E_BADPRECISION")
	TEST_VARIATION(36, 		L"invalid scale on column => DB_E_BADSCALE")
	TEST_VARIATION(37, 		L"col prop is not in the Column, Rowset or Table property group and dwOption is DBPROP_SETIFCHEAP => DB_S_ERRORSOCCURRED")
	TEST_VARIATION(38, 		L"col prop is not in the Column, Rowset or Table property group and dwOption is DBPROP_REQUIRED => DB_E_ERRORSOCCURRED")
	TEST_VARIATION(39, 		L"invalid propID for a column propriety")
	TEST_VARIATION(40, 		L"colid in DBPROP of a column property is ignored")
	TEST_VARIATION(41, 		L"Abort retaining")
	TEST_VARIATION(42, 		L"Abort without retaining")
	TEST_VARIATION(43, 		L"Commit retain")
	TEST_VARIATION(44, 		L"Commit non-retaining")
	TEST_VARIATION(45, 		L"Autoincrementable columns")
	TEST_VARIATION(46, 		L"Default values")
	TEST_VARIATION(47, 		L"Column descriptions")
	TEST_VARIATION(48, 		L"Variable length columns")
	TEST_VARIATION(49, 		L"Nullable/non nullable columns")
	TEST_VARIATION(50, 		L"Primary key column")
	TEST_VARIATION(51, 		L"Unique columns")
	TEST_VARIATION(52, 		L"Test conflicting properties")
	TEST_VARIATION(53, 		L"Create a table and ask for a rowset, setting DBPROP_ABORTPRESERVE")
	TEST_VARIATION(54, 		L"Inserting rows after table creation, using the resulting rowset")
	TEST_VARIATION(55, 		L"Delete rows in the created rowset")
	TEST_VARIATION(56, 		L"Aggregation, ask for IID_IUnknown")
	TEST_VARIATION(57, 		L"Create a table and ask for a rowset, setting DBPROP_COMMITPRESERVE")
	TEST_VARIATION(58, 		L"Create a table and ask for a rowset, setting DBPROP_OWNINSERT")
	TEST_VARIATION(59, 		L"Create a table and ask for a rowset, setting DBPROP_BOOKMARKS")
	TEST_VARIATION(60, 		L"Create a table and ask for a rowset, setting DBPROP_CANHOLDROWS")
	TEST_VARIATION(61, 		L"Create a table and ask for a rowset, setting DBPROP_MAYWRITECOLUMN")
	TEST_VARIATION(62, 		L"Ask for a rowset mandatory/optional interface when table creation => S_OK")
	TEST_VARIATION(63, 		L"threads on different tables")
	TEST_VARIATION(64, 		L"threads on the same table")
	TEST_VARIATION(65, 		L"try all interfaces on rowset that can be returned")
	TEST_VARIATION(66, 		L"create with a table property => S_OK")
	TEST_VARIATION(67, 		L"create a table and update a row, using the rowset interface got => S_OK")
	TEST_VARIATION(68, 		L"Fully Qualified Table Name")
	TEST_VARIATION(69, 		L"Quoted table name")
	TEST_VARIATION(70, 		L"Aggregation, non IID_IUnknown")
	TEST_VARIATION(71, 		L"Aggregation -> IRowsetInfo::GetReferencedRowset")
	TEST_VARIATION(72, 		L"Agg session -> IRowsetInfo::GetSpecification")
	TEST_VARIATION(73, 		L"Table -> Agg ColumnRowset, ask for non IID_IUnknown")
	TEST_VARIATION(74, 		L"Table -> Agg ColumnRowset, ask for IID_IUnknown")
	TEST_VARIATION(75, 		L"Table -> Agg ColumnRowset -> IRowsetInfo::GetSpecification")
	TEST_VARIATION(76, 		L"colid is ignored in a non column specific rowset property")
	TEST_VARIATION(77, 		L"colid is DB_NULLID in a column specific rowset property => S_OK")
	TEST_VARIATION(78, 		L"valid, non DB_NULLID colid for a column specific rowset property")
	TEST_VARIATION(79, 		L"invalid colid for a column specific rowset property")
	TEST_VARIATION(80, 		L"Create a table. Retrieve a rowset on it (IRowsetInfo). Check GetSpecification()")
	TEST_VARIATION(81, 		L"DB_NULLID is ignored for non column-related table properties")
	TEST_VARIATION(82, 		L"Column related table property set to bad colid")
	TEST_VARIATION(83, 		L"How many DBTYPE_I4 columns?")
	TEST_VARIATION(84, 		L"Open a rowset with CE, call IColumnRowset with an aggregated pIUnk")
	TEST_VARIATION(85, 		L"Different DBKINDs for pTableID")
	TEST_VARIATION(86, 		L"Different DBKINDs for column IDs")
END_TEST_CASE()
#undef THE_CLASS
// }} TCW_TESTCASE_END
// }} TCW_TEST_CASE_MAP_END


// {{ TCW_TEST_CASE_MAP(RODataSource)
//--------------------------------------------------------------------
// @class Test case for operating on a read only data source
//
class RODataSource : public TCDropColumn { 
private:
	// @cmember Static array of variations
	DECLARE_TEST_CASE_DATA();
	IUnknown			*m_pIUnknown;
	IUnknown			*m_pIUnknown2;
	ITableDefinition	*m_pITableDefinition2;

public:
	// {{ TCW_DECLARE_FUNCS
	// @cmember Execution Routine
	DECLARE_TEST_CASE_FUNCS(RODataSource,TCDropColumn);
	// }} TCW_DECLARE_FUNCS_END
	
	// @cmember Initialization Routine
	virtual BOOL Init();
	// @cmember Termination Routine
	virtual BOOL Terminate();

	// {{ TCW_TESTVARS()
	// @cmember Add a column
	int Variation_1();
	// @cmember Drop a column
	int Variation_2();
	// @cmember Create a table
	int Variation_3();
	// @cmember Drop a table
	int Variation_4();
	// }} TCW_TESTVARS_END
} ;

// {{ TCW_TESTCASE(RODataSource)
#define THE_CLASS RODataSource
BEG_TEST_CASE(RODataSource, TCDropColumn, L"Test case for operating on a read only data source")
	TEST_VARIATION(1, 		L"Add a column")
	TEST_VARIATION(2, 		L"Drop a column")
	TEST_VARIATION(3, 		L"Create a table")
	TEST_VARIATION(4, 		L"Drop a table")
END_TEST_CASE()
#undef THE_CLASS
// }} TCW_TESTCASE_END
// }} TCW_TEST_CASE_MAP_END

// {{ TCW_TEST_CASE_MAP(TCAddConstraint_Boundary)
//*-----------------------------------------------------------------------
// @class General and boundary/null test for ITableDefinitionWithConstraints::AddConstraint
//
class TCAddConstraint_Boundary : public TCITableDefinition { 
private:
	// @cmember Static array of variations
	DECLARE_TEST_CASE_DATA();

public:
	// {{ TCW_DECLARE_FUNCS
	// @cmember Execution Routine
	DECLARE_TEST_CASE_FUNCS(TCAddConstraint_Boundary,TCITableDefinition);
	// }} TCW_DECLARE_FUNCS_END
	
	// @cmember Initialization Routine
	virtual BOOL Init();
	// @cmember Termination Routine
	virtual BOOL Terminate();

	// {{ TCW_TESTVARS()
	// @cmember Check the session object (QI for interfaces)
	int Variation_1();
	// @cmember pTableID is NULL => E_INVALIDARG
	int Variation_2();
	// @cmember *pTableID is DB_NULLID => DB_E_NOTABLE
	int Variation_3();
	// @cmember Table name is NULL => DB_E_NOTABLE
	int Variation_4();
	// @cmember Table name is the empty string => DB_E_NOTABLE
	int Variation_5();
	// @cmember Table name has maximum length
	int Variation_6();
	// @cmember Table name exceeds maximum length => DB_E_NOTABLE
	int Variation_7();
	// @cmember Table name contains illegal characters
	int Variation_8();
	// @cmember Invalid DBKIND value for the base table
	int Variation_9();
	// @cmember NULL column list in a constraint, column size is not 0 => E_INVALIDARG
	int Variation_10();
	// @cmember NULL column name in a constraint
	int Variation_11();
	// @cmember Empty string for a column name
	int Variation_12();
	// @cmember Maximum length column name in a constraint
	int Variation_13();
	// @cmember Column name exceeds maximum length
	int Variation_14();
	// @cmember Invalid DBKIND for a column DBID of a constraint
	int Variation_15();
	// @cmember Column ID is DB_NULLID
	int Variation_16();
	// @cmember NULL pReferencedTableID for a foreign key constraint (with and without cForeignKeyColumns being 0)
	int Variation_17();
	// @cmember DBNULL_ID *pReferencedTableID for a foreign key constraint
	int Variation_18();
	// @cmember NULL referenced table name for a foreign key constraint
	int Variation_19();
	// @cmember Emptry string referenced table name for a foreign key constraint
	int Variation_20();
	// @cmember Maximum length referenced table name for a foreign key constraint
	int Variation_21();
	// @cmember Referenced table name longer than allowed for a foreign key constraint
	int Variation_22();
	// @cmember Illegal characters in the referenced table name for a foreign key constraint
	int Variation_23();
	// @cmember Bad constraint type
	int Variation_24();
	// @cmember Empty list of columns for a unique, primay key or foreign key constraint
	int Variation_25();
	// @cmember Non empty list of columns for a check constraint
	int Variation_26();
	// @cmember Not null pwszConstraintText in a unique, PK or FK constraint
	int Variation_27();
	// @cmember NULL pConstraintDesc => E_INVALIDARG
	int Variation_28();
	// @cmember 0 < cColumns and NULL == rgColumnList => E_INVALIDARG
	int Variation_29();
	// @cmember 0 < cForeignKeyColumns and NULL == rgForeignKeyColumnList => E_INVALIDARG
	int Variation_30();
	// @cmember Constraint is not foreign key and pReferencedTableID is not NULL
	int Variation_31();
	// @cmember Non empty list of foreign keys for a constraint that is not foreign key
	int Variation_32();
	// @cmember Inexistent referenced table
	int Variation_33();
	// @cmember Add several constraints to the table
	int Variation_34();
	// @cmember Inexistent table name => DB_E_NOTABLE
	int Variation_35();
	// @cmember Inexistent column name => DB_E_NOCOLUMN
	int Variation_36();
	// }} TCW_TESTVARS_END
} ;
// {{ TCW_TESTCASE(TCAddConstraint_Boundary)
#define THE_CLASS TCAddConstraint_Boundary
BEG_TEST_CASE(TCAddConstraint_Boundary, TCITableDefinition, L"General and boundary/null test for ITableDefinitionWithConstraints::AddConstraint")
	TEST_VARIATION(1, 		L"Check the session object (QI for interfaces)")
	TEST_VARIATION(2, 		L"pTableID is NULL => E_INVALIDARG")
	TEST_VARIATION(3, 		L"*pTableID is DB_NULLID => DB_E_NOTABLE")
	TEST_VARIATION(4, 		L"Table name is NULL => DB_E_NOTABLE")
	TEST_VARIATION(5, 		L"Table name is the empty string => DB_E_NOTABLE")
	TEST_VARIATION(6, 		L"Table name has maximum length")
	TEST_VARIATION(7, 		L"Table name exceeds maximum length => DB_E_NOTABLE")
	TEST_VARIATION(8, 		L"Table name contains illegal characters")
	TEST_VARIATION(9, 		L"Invalid DBKIND value for the base table")
	TEST_VARIATION(10, 		L"NULL column list in a constraint, column size is not 0 => E_INVALIDARG")
	TEST_VARIATION(11, 		L"NULL column name in a constraint")
	TEST_VARIATION(12, 		L"Empty string for a column name")
	TEST_VARIATION(13, 		L"Maximum length column name in a constraint")
	TEST_VARIATION(14, 		L"Column name exceeds maximum length")
	TEST_VARIATION(15, 		L"Invalid DBKIND for a column DBID of a constraint")
	TEST_VARIATION(16, 		L"Column ID is DB_NULLID")
	TEST_VARIATION(17, 		L"NULL pReferencedTableID for a foreign key constraint (with and without cForeignKeyColumns being 0)")
	TEST_VARIATION(18, 		L"DBNULL_ID *pReferencedTableID for a foreign key constraint")
	TEST_VARIATION(19, 		L"NULL referenced table name for a foreign key constraint")
	TEST_VARIATION(20, 		L"Emptry string referenced table name for a foreign key constraint")
	TEST_VARIATION(21, 		L"Maximum length referenced table name for a foreign key constraint")
	TEST_VARIATION(22, 		L"Referenced table name longer than allowed for a foreign key constraint")
	TEST_VARIATION(23, 		L"Illegal characters in the referenced table name for a foreign key constraint")
	TEST_VARIATION(24, 		L"Bad constraint type")
	TEST_VARIATION(25, 		L"Empty list of columns for a unique, primay key or foreign key constraint")
	TEST_VARIATION(26, 		L"Non empty list of columns for a check constraint")
	TEST_VARIATION(27, 		L"Not null pwszConstraintText in a unique, PK or FK constraint")
	TEST_VARIATION(28, 		L"NULL pConstraintDesc => E_INVALIDARG")
	TEST_VARIATION(29, 		L"0 < cColumns and NULL == rgColumnList => E_INVALIDARG")
	TEST_VARIATION(30, 		L"0 < cForeignKeyColumns and NULL == rgForeignKeyColumnList => E_INVALIDARG")
	TEST_VARIATION(31, 		L"Constraint is not foreign key and pReferencedTableID is not NULL")
	TEST_VARIATION(32, 		L"Non empty list of foreign keys for a constraint that is not foreign key")
	TEST_VARIATION(33, 		L"Inexistent referenced table")
	TEST_VARIATION(34, 		L"Add several constraints to the table")
	TEST_VARIATION(35, 		L"Inexistent table name => DB_E_NOTABLE")
	TEST_VARIATION(36, 		L"Inexistent column name => DB_E_NOCOLUMN")
END_TEST_CASE()
#undef THE_CLASS
// }} TCW_TESTCASE_END
// }} TCW_TEST_CASE_MAP_END

// {{ TCW_TEST_CASE_MAP(TCAddConstraint_UNIQUE)
//*-----------------------------------------------------------------------
// @class Testcase for ITableDefinitionWithConstraints::AddConstraint used with DBCONSTRAINTTYPE_UNIQUE
//
class TCAddConstraint_UNIQUE : public TCITableDefinition { 
private:
	// @cmember Static array of variations
	DECLARE_TEST_CASE_DATA();

public:
	// {{ TCW_DECLARE_FUNCS
	// @cmember Execution Routine
	DECLARE_TEST_CASE_FUNCS(TCAddConstraint_UNIQUE,TCITableDefinition);
	// }} TCW_DECLARE_FUNCS_END
	
	// @cmember Initialization Routine
	virtual BOOL Init();
	// @cmember Termination Routine
	virtual BOOL Terminate();

	// {{ TCW_TESTVARS()
	// @cmember Create a table and try to apply the constraint on each column
	int Variation_1();
	// @cmember Set a unique constraint on each type of column
	int Variation_2();
	// @cmember Create a unique constraint that uses several columns
	int Variation_3();
	// @cmember Create several unique constraints on a table, no overlapping
	int Variation_4();
	// @cmember Create multiple, overlapping constraints on a table
	int Variation_5();
	// @cmember Create a constraint, drop it and recreate it
	int Variation_6();
	// @cmember Create a constraint on a null column
	int Variation_7();
	// @cmember Create a contraint on a not nullable column
	int Variation_8();
	// @cmember Create a constraint on a column that has a default value
	int Variation_9();
	// @cmember Create a constraint on a column defined as a primary key
	int Variation_10();
	// @cmember Create a constraint on a column defined as a foreign key
	int Variation_11();
	// @cmember Create a constraint on a column that is included in an index
	int Variation_12();
	// @cmember Use the name of an already existing constraint
	int Variation_13();
	// @cmember Constraint is created in a different catalog
	int Variation_14();
	// @cmember create a unique constraint on a non empty table
	int Variation_15();
	// @cmember Create a unique constraints on a column that has doubled values
	int Variation_16();
	// @cmember Abort retaining
	int Variation_17();
	// @cmember Abort non retaining
	int Variation_18();
	// @cmember Commit retaining
	int Variation_19();
	// @cmember Commit non retaining
	int Variation_20();
	// @cmember Maximum columns allowed in Unique constraint
	int Variation_21();
	// }} TCW_TESTVARS_END
} ;
// {{ TCW_TESTCASE(TCAddConstraint_UNIQUE)
#define THE_CLASS TCAddConstraint_UNIQUE
BEG_TEST_CASE(TCAddConstraint_UNIQUE, TCITableDefinition, L"Testcase for ITableDefinitionWithConstraints::AddConstraint used with DBCONSTRAINTTYPE_UNIQUE")
	TEST_VARIATION(1, 		L"Create a table and try to apply the constraint on each column")
	TEST_VARIATION(2, 		L"Set a unique constraint on each type of column")
	TEST_VARIATION(3, 		L"Create a unique constraint that uses several columns")
	TEST_VARIATION(4, 		L"Create several unique constraints on a table, no overlapping")
	TEST_VARIATION(5, 		L"Create multiple, overlapping constraints on a table")
	TEST_VARIATION(6, 		L"Create a constraint, drop it and recreate it")
	TEST_VARIATION(7, 		L"Create a constraint on a null column")
	TEST_VARIATION(8, 		L"Create a contraint on a not nullable column")
	TEST_VARIATION(9, 		L"Create a constraint on a column that has a default value")
	TEST_VARIATION(10, 		L"Create a constraint on a column defined as a primary key")
	TEST_VARIATION(11, 		L"Create a constraint on a column defined as a foreign key")
	TEST_VARIATION(12, 		L"Create a constraint on a column that is included in an index")
	TEST_VARIATION(13, 		L"Use the name of an already existing constraint")
	TEST_VARIATION(14, 		L"Constraint is created in a different catalog")
	TEST_VARIATION(15, 		L"create a unique constraint on a non empty table")
	TEST_VARIATION(16, 		L"Create a unique constraints on a column that has doubled values")
	TEST_VARIATION(17, 		L"Abort retaining")
	TEST_VARIATION(18, 		L"Abort non retaining")
	TEST_VARIATION(19, 		L"Commit retaining")
	TEST_VARIATION(20, 		L"Commit non retaining")
	TEST_VARIATION(21,		L"Maximum columns allowed in unique constraint")
END_TEST_CASE()
#undef THE_CLASS
// }} TCW_TESTCASE_END
// }} TCW_TEST_CASE_MAP_END

// {{ TCW_TEST_CASE_MAP(TCAddConstraint_PRIMARYKEY)
//*-----------------------------------------------------------------------
// @class Testcase for ITableDefinitionWithConstraints::AddConstraint used with DBCONSTRAINTTYPE_PRIMARYKEY
//
class TCAddConstraint_PRIMARYKEY : public TCITableDefinition { 
private:
	// @cmember Static array of variations
	DECLARE_TEST_CASE_DATA();

public:
	// {{ TCW_DECLARE_FUNCS
	// @cmember Execution Routine
	DECLARE_TEST_CASE_FUNCS(TCAddConstraint_PRIMARYKEY,TCITableDefinition);
	// }} TCW_DECLARE_FUNCS_END
	
	// @cmember Initialization Routine
	virtual BOOL Init();
	// @cmember Termination Routine
	virtual BOOL Terminate();

	// {{ TCW_TESTVARS()
	// @cmember Create a table and try to apply the constraint on each column
	int Variation_1();
	// @cmember Set a primary key constraint on each type of column
	int Variation_2();
	// @cmember Create a primary key constraint. Drop it. Create a primary key using the same name as before.
	int Variation_3();
	// @cmember Create multiple-columned primary key
	int Variation_4();
	// @cmember Create multiple primary key constraints using successive calls
	int Variation_5();
	// @cmember Successive calls, lists of columns overlap
	int Variation_6();
	// @cmember Primary key constraint on a nullable column
	int Variation_7();
	// @cmember Primary key constraint on a not nullable column
	int Variation_8();
	// @cmember Primary key constraint on a column with a default value
	int Variation_9();
	// @cmember Primary key constraint on a column defined as unique
	int Variation_10();
	// @cmember Primary key constraint on a column defined as primary key => DB_E_DUPLICATECONSTRAINTID
	int Variation_11();
	// @cmember Primary key constraint on a column that already has a primary key constraint
	int Variation_12();
	// @cmember Primary key constraint on a column that is part of a foreign key constraint
	int Variation_13();
	// @cmember Primary key constraint on a column that is part of an index
	int Variation_14();
	// @cmember Primary key constraint on a column on a not empty table
	int Variation_15();
	// @cmember Primary key constraint on a column that already has duplicates (for the whole key)
	int Variation_16();
	// @cmember Primary key constraint that has duplicates for a column in the key, but not for the whole key
	int Variation_17();
	// @cmember Abort retaining
	int Variation_18();
	// @cmember Abort non retaining
	int Variation_19();
	// @cmember Commit retaining
	int Variation_20();
	// @cmember Commit non retaining
	int Variation_21();
	// @cmember Create PK in different catalog
	int Variation_22();
	// @cmember Find maximum limit on PKs
	int Variation_23();
	// }} TCW_TESTVARS_END
} ;
// {{ TCW_TESTCASE(TCAddConstraint_PRIMARYKEY)
#define THE_CLASS TCAddConstraint_PRIMARYKEY
BEG_TEST_CASE(TCAddConstraint_PRIMARYKEY, TCITableDefinition, L"Testcase for ITableDefinitionWithConstraints::AddConstraint used with DBCONSTRAINTTYPE_PRIMARYKEY")
	TEST_VARIATION(1, 		L"Create a table and try to apply the constraint on each column")
	TEST_VARIATION(2, 		L"Set a primary key constraint on each type of column")
	TEST_VARIATION(3, 		L"Create a primary key constraint. Drop it. Create a primary key using the same name as before.")
	TEST_VARIATION(4, 		L"Create multiple-columned primary key")
	TEST_VARIATION(5, 		L"Create multiple primary key constraints using successive calls")
	TEST_VARIATION(6, 		L"Successive calls, lists of columns overlap")
	TEST_VARIATION(7, 		L"Primary key constraint on a nullable column -> E_FAIL")
	TEST_VARIATION(8, 		L"Primary key constraint on a not nullable column")
	TEST_VARIATION(9, 		L"Primary key constraint on a column with a default value")
	TEST_VARIATION(10, 		L"Primary key constraint on a column defined as unique")
	TEST_VARIATION(11, 		L"Primary key constraint on a column defined as primary key => DB_E_DUPLICATECONSTRAINTID")
	TEST_VARIATION(12, 		L"Primary key constraint on a column that already has a primary key constraint")
	TEST_VARIATION(13, 		L"Primary key constraint on a column that is part of a foreign key constraint")
	TEST_VARIATION(14, 		L"Primary key constraint on a column that is part of an index")
	TEST_VARIATION(15, 		L"Primary key constraint on a column on a not empty table")
	TEST_VARIATION(16, 		L"Primary key constraint on a column that already has duplicates (for the whole key)")
	TEST_VARIATION(17, 		L"Primary key constraint that has duplicates for a column in the key, but not for the whole key")
	TEST_VARIATION(18, 		L"Abort retaining")
	TEST_VARIATION(19, 		L"Abort non retaining")
	TEST_VARIATION(20, 		L"Commit retaining")
	TEST_VARIATION(21, 		L"Commit non retaining")
	TEST_VARIATION(22,		L"Create primary key in a different catalog")
	TEST_VARIATION(23,		L"Find how many columns are supported in a PK")
END_TEST_CASE()
#undef THE_CLASS
// }} TCW_TESTCASE_END
// }} TCW_TEST_CASE_MAP_END

// {{ TCW_TEST_CASE_MAP(TCAddConstraint_FOREIGNKEY)
//*-----------------------------------------------------------------------
// @class Testcase for ITableDefinitionWithConstraints::AddConstraint used with DBCONSTRAINTTYPE_FOREIGNKEY
//
class TCAddConstraint_FOREIGNKEY : public TCITableDefinition { 
private:
	// @cmember Static array of variations
	DECLARE_TEST_CASE_DATA();
	CTable			*m_pReferenceTable;

public:
	// {{ TCW_DECLARE_FUNCS
	// @cmember Execution Routine
	DECLARE_TEST_CASE_FUNCS(TCAddConstraint_FOREIGNKEY,TCITableDefinition);
	// }} TCW_DECLARE_FUNCS_END
	
	// @cmember Initialization Routine
	virtual BOOL Init();
	// @cmember Termination Routine
	virtual BOOL Terminate();

	// {{ TCW_TESTVARS()
	// @cmember Simple foreign key constraint
	int Variation_1();
	// @cmember Foregin key is made of several columns
	int Variation_2();
	// @cmember Multiple foreign key constraints on a table
	int Variation_3();
	// @cmember Multiple overlapping foreign key constraints
	int Variation_4();
	// @cmember Create a foreign key on each column of the table
	int Variation_5();
	// @cmember Create a foreign key on all columns
	int Variation_6();
	// @cmember Create foreign key and try to drop the reference table
	int Variation_7();
	// @cmember On a nullable column
	int Variation_8();
	// @cmember On a not nullable column
	int Variation_9();
	// @cmember On a column having a default value
	int Variation_10();
	// @cmember On a column defined as unique
	int Variation_11();
	// @cmember On a primary key column
	int Variation_12();
	// @cmember On a column that is part of the index
	int Variation_13();
	// @cmember On a table that is in another catalog
	int Variation_14();
	// @cmember Use different combination for update/delete rules, as well as match type
	int Variation_15();
	// @cmember Referenced table name and base table names have maximum length
	int Variation_16();
	// @cmember Columns in the foreign key (base table and reference table) have different names
	int Variation_17();
	// @cmember Different size in column lists (base table and referenced)
	int Variation_18();
	// @cmember Column types in base table and reference table are different
	int Variation_19();
	// @cmember Invalid value for the update rule
	int Variation_20();
	// @cmember Invalid value for the delete rule
	int Variation_21();
	// @cmember Invalid value for the MatchType
	int Variation_22();
	// @cmember Inexistent column names in the referenced table
	int Variation_23();
	// @cmember Inexistent column name in the base table
	int Variation_24();
	// @cmember Inexistent base table
	int Variation_25();
	// @cmember Inexistent reference table
	int Variation_26();
	// @cmember NULL pConstraintID
	int Variation_27();
	// @cmember Referenced col list is not a unique / pk constraint => failure
	int Variation_28();
	// @cmember Create a foreign key and then insert a NULL value for one of the fk columns
	int Variation_29();
	// @cmember The referenced table and the base table are the same
	int Variation_30();
	// @cmember The base and referenced tables are temporary tables
	int Variation_31();
	// @cmember Base table is a temporary table
	int Variation_32();
	// @cmember Abort retaining
	int Variation_33();
	// @cmember Abort non retaining
	int Variation_34();
	// @cmember Commit retaining
	int Variation_35();
	// @cmember Commit non retaining
	int Variation_36();
	// @cmember The base table is already populated and the referenced one is empty => DB_E_SCHEMAVIOLATION
	int Variation_37();
	// @cmember Find maximum columns allowed in foreign keys
	int Variation_38();
	// }} TCW_TESTVARS_END
} ;
// {{ TCW_TESTCASE(TCAddConstraint_FOREIGNKEY)
#define THE_CLASS TCAddConstraint_FOREIGNKEY
BEG_TEST_CASE(TCAddConstraint_FOREIGNKEY, TCITableDefinition, L"Testcase for ITableDefinitionWithConstraints::AddConstraint used with DBCONSTRAINTTYPE_FOREIGNKEY")
	TEST_VARIATION(1, 		L"Simple foreign key constraint")
	TEST_VARIATION(2, 		L"Foregin key is made of several columns")
	TEST_VARIATION(3, 		L"Multiple foreign key constraints on a table")
	TEST_VARIATION(4, 		L"Multiple overlapping foreign key constraints")
	TEST_VARIATION(5, 		L"Create a foreign key on each column of the table")
	TEST_VARIATION(6, 		L"Create a foreign key on all columns")
	TEST_VARIATION(7, 		L"Create foreign key and try to drop the reference table")
	TEST_VARIATION(8, 		L"On a nullable column")
	TEST_VARIATION(9, 		L"On a not nullable column")
	TEST_VARIATION(10, 		L"On a column having a default value")
	TEST_VARIATION(11, 		L"On a column defined as unique")
	TEST_VARIATION(12, 		L"On a primary key column")
	TEST_VARIATION(13, 		L"On a column that is part of the index")
	TEST_VARIATION(14, 		L"On a table that is in another catalog")
	TEST_VARIATION(15, 		L"Use different combination for update/delete rules, as well as match type")
	TEST_VARIATION(16, 		L"Referenced table name and base table names have maximum length")
	TEST_VARIATION(17, 		L"Columns in the foreign key (base table and reference table) have different names")
	TEST_VARIATION(18, 		L"Different size in column lists (base table and referenced)")
	TEST_VARIATION(19, 		L"Column types in base table and reference table are different")
	TEST_VARIATION(20, 		L"Invalid value for the update rule")
	TEST_VARIATION(21, 		L"Invalid value for the delete rule")
	TEST_VARIATION(22, 		L"Invalid value for the MatchType")
	TEST_VARIATION(23, 		L"Inexistent column names in the referenced table")
	TEST_VARIATION(24, 		L"Inexistent column name in the base table")
	TEST_VARIATION(25, 		L"Inexistent base table")
	TEST_VARIATION(26, 		L"Inexistent reference table")
	TEST_VARIATION(27, 		L"NULL pConstraintID")
	TEST_VARIATION(28, 		L"Referenced col list is not a unique / pk constraint => failure")
	TEST_VARIATION(29, 		L"Create a foreign key and then insert a NULL value for one of the fk columns")
	TEST_VARIATION(30, 		L"The referenced table and the base table are the same")
	TEST_VARIATION(31, 		L"The base and referenced tables are temporary tables")
	TEST_VARIATION(32, 		L"Base table is a temporary table")
	TEST_VARIATION(33, 		L"Abort retaining")
	TEST_VARIATION(34, 		L"Abort non retaining")
	TEST_VARIATION(35, 		L"Commit retaining")
	TEST_VARIATION(36, 		L"Commit non retaining")
	TEST_VARIATION(37, 		L"The base table is already populated and the referenced one is empty => DB_E_SCHEMAVIOLATION")
	TEST_VARIATION(38,		L"Find maximum columns allowed in foreign keys")
END_TEST_CASE()
#undef THE_CLASS
// }} TCW_TESTCASE_END
// }} TCW_TEST_CASE_MAP_END

// {{ TCW_TEST_CASE_MAP(TCAddConstraint_CHECK)
//*-----------------------------------------------------------------------
// @class Testcase for ITableDefinitionWithConstraints::AddConstraint used with DBCONSTRAINTTYPE_UNIQUE
//
class TCAddConstraint_CHECK : public TCITableDefinition { 
private:
	// @cmember Static array of variations
	DECLARE_TEST_CASE_DATA();

public:
	// {{ TCW_DECLARE_FUNCS
	// @cmember Execution Routine
	DECLARE_TEST_CASE_FUNCS(TCAddConstraint_CHECK,TCITableDefinition);
	// }} TCW_DECLARE_FUNCS_END
	
	// @cmember Initialization Routine
	virtual BOOL Init();
	// @cmember Termination Routine
	virtual BOOL Terminate();

	// {{ TCW_TESTVARS()
	// @cmember Add simple check constraint
	int Variation_1();
	// @cmember Add 2 check constraints on the same column
	int Variation_2();
	// @cmember Add check constraint for each column
	int Variation_3();
	// @cmember Check constraint is always TRUE
	int Variation_4();
	// @cmember Check constraint is always false
	int Variation_5();
	// @cmember Long text for the check constraint
	int Variation_6();
	// @cmember Check constraint is made of white characters
	int Variation_7();
	// @cmember Maximum length for the table name
	int Variation_8();
	// @cmember Create the constraint, drop it, readd it with different text
	int Variation_9();
	// @cmember Use inexistent column names in the check constraint
	int Variation_10();
	// @cmember Use qualified table column with different table
	int Variation_11();
	// @cmember Set a check condition on an index column
	int Variation_12();
	// @cmember pwszConstraintText is NULL
	int Variation_13();
	// @cmember pwszConstraintText is an empty string
	int Variation_14();
	// @cmember Abort retaining
	int Variation_15();
	// @cmember Abort non retaining
	int Variation_16();
	// @cmember Commit retaining
	int Variation_17();
	// @cmember Commit non retaining
	int Variation_18();
	// @cmember Table is populated with rows that break the constraint to be added => DB_E_SCHEMAVIOLATION
	int Variation_19();
	// @cmember Create check constraint in different catalog
	int Variation_20();
	// }} TCW_TESTVARS_END
} ;
// {{ TCW_TESTCASE(TCAddConstraint_CHECK)
#define THE_CLASS TCAddConstraint_CHECK
BEG_TEST_CASE(TCAddConstraint_CHECK, TCITableDefinition, L"Testcase for ITableDefinitionWithConstraints::AddConstraint used with DBCONSTRAINTTYPE_UNIQUE")
	TEST_VARIATION(1, 		L"Add simple check constraint")
	TEST_VARIATION(2, 		L"Add 2 check constraints on the same column")
	TEST_VARIATION(3, 		L"Add check constraint for each column")
	TEST_VARIATION(4, 		L"Check constraint is always TRUE")
	TEST_VARIATION(5, 		L"Check constraint is always false")
	TEST_VARIATION(6, 		L"Long text for the check constraint")
	TEST_VARIATION(7, 		L"Check constraint is made of white characters")
	TEST_VARIATION(8, 		L"Maximum length for the table name")
	TEST_VARIATION(9, 		L"Create the constraint, drop it, readd it with different text")
	TEST_VARIATION(10, 		L"Use inexistent column names in the check constraint")
	TEST_VARIATION(11, 		L"Use qualified table column with different table")
	TEST_VARIATION(12, 		L"Set a check condition on an index column")
	TEST_VARIATION(13, 		L"pwszConstraintText is NULL")
	TEST_VARIATION(14, 		L"pwszConstraintText is an empty string")
	TEST_VARIATION(15, 		L"Abort retaining")
	TEST_VARIATION(16, 		L"Abort non retaining")
	TEST_VARIATION(17, 		L"Commit retaining")
	TEST_VARIATION(18, 		L"Commit non retaining")
	TEST_VARIATION(19, 		L"Table is populated with rows that break the constraint to be added => DB_E_SCHEMAVIOLATION")
	TEST_VARIATION(20,		L"Check constraint is created on a table in different catalog")
END_TEST_CASE()
#undef THE_CLASS
// }} TCW_TESTCASE_END
// }} TCW_TEST_CASE_MAP_END

// {{ TCW_TEST_CASE_MAP(TCAddConstraint_Deferrability)
//*-----------------------------------------------------------------------
// @class Testcase for ITableDefinitionWithConstraints::AddConstraint used with deferrability setting
//
class TCAddConstraint_Deferrability : public TCITableDefinition { 
private:
	// @cmember Static array of variations
	DECLARE_TEST_CASE_DATA();

public:
	// {{ TCW_DECLARE_FUNCS
	// @cmember Execution Routine
	DECLARE_TEST_CASE_FUNCS(TCAddConstraint_Deferrability,TCITableDefinition);
	// }} TCW_DECLARE_FUNCS_END
	
	// @cmember Initialization Routine
	virtual BOOL Init();
	// @cmember Termination Routine
	virtual BOOL Terminate();

	// {{ TCW_TESTVARS()
	// @cmember Immediate unique constraint
	int Variation_1();
	// @cmember Defferable unique constraint
	int Variation_2();
	// @cmember Deffered unique constraint
	int Variation_3();
	// @cmember Bad deferrability value unique constraint
	int Variation_4();
	// @cmember Immediate primary key constraint
	int Variation_5();
	// @cmember Deferrable primary key constraint
	int Variation_6();
	// @cmember Deferred primary key constraint
	int Variation_7();
	// @cmember Bad deferrability value primary key constraint
	int Variation_8();
	// @cmember Immediate foreign key constraint
	int Variation_9();
	// @cmember Deferrable foreign key constraint
	int Variation_10();
	// @cmember Deferred foreign key constraint
	int Variation_11();
	// @cmember Bad deferrability value foreign key constraint
	int Variation_12();
	// @cmember Immediate check constraint
	int Variation_13();
	// @cmember Deferrable check constraint
	int Variation_14();
	// @cmember Deferred check constraint
	int Variation_15();
	// @cmember Bad deferrability value check constraint
	int Variation_16();
	// }} TCW_TESTVARS_END
} ;
// {{ TCW_TESTCASE(TCAddConstraint_Deferrability)
#define THE_CLASS TCAddConstraint_Deferrability
BEG_TEST_CASE(TCAddConstraint_Deferrability, TCITableDefinition, L"Testcase for ITableDefinitionWithConstraints::AddConstraint used with deferrability setting")
	TEST_VARIATION(1, 		L"Immediate unique constraint")
	TEST_VARIATION(2, 		L"Defferable unique constraint")
	TEST_VARIATION(3, 		L"Deffered unique constraint")
	TEST_VARIATION(4, 		L"Bad deferrability value unique constraint")
	TEST_VARIATION(5, 		L"Immediate primary key constraint")
	TEST_VARIATION(6, 		L"Deferrable primary key constraint")
	TEST_VARIATION(7, 		L"Deferred primary key constraint")
	TEST_VARIATION(8, 		L"Bad deferrability value primary key constraint")
	TEST_VARIATION(9, 		L"Immediate foreign key constraint")
	TEST_VARIATION(10, 		L"Deferrable foreign key constraint")
	TEST_VARIATION(11, 		L"Deferred foreign key constraint")
	TEST_VARIATION(12, 		L"Bad deferrability value foreign key constraint")
	TEST_VARIATION(13, 		L"Immediate check constraint")
	TEST_VARIATION(14, 		L"Deferrable check constraint")
	TEST_VARIATION(15, 		L"Deferred check constraint")
	TEST_VARIATION(16, 		L"Bad deferrability value check constraint")
END_TEST_CASE()
#undef THE_CLASS
// }} TCW_TESTCASE_END
// }} TCW_TEST_CASE_MAP_END


// {{ TCW_TEST_CASE_MAP(TCCreateTableWithConstraints_NoConstraint)
//*-----------------------------------------------------------------------
// @class Testcase for ITableDefinitionWithConstraints::AddConstraint used with deferrability setting
//
class TCCreateTableWithConstraints_NoConstraint : public TCCreateTable { 
public:
	//DECLARE_TEST_CASE_DATA();
	ITableDefinitionWithConstraints		*m_pITableDefinitionWithConstraints;

public:
	static const WCHAR		m_wszTestCaseName[];		
    static const WCHAR		m_wszTestCaseDesc[];		
	// {{ TCW_DECLARE_FUNCS
	// @cmember Execution Routine
	DECLARE_TEST_CASE_FUNCS(TCCreateTableWithConstraints_NoConstraint,TCCreateTable);
	// }} TCW_DECLARE_FUNCS_END

	// @member Create the table using ITableDefinition::CreateTable and check its creation
	virtual HRESULT	CreateAndCheckTable(
		ITableDefinition	*pITableDefinitionWithConstraints,	// [in] pointer to the ITableDefinition interface to be used
		IUnknown			*pUnkOuter,			// [in] pointer to controlling unknown
		DBID				*pTableID,			// [in]	pointer to the input table ID
		DBORDINAL			cColumnDescs,		// [in]	the number of columns to be created
		DBCOLUMNDESC		*rgColumnDesc,		// [in/out] array of columns to be created
		REFIID				riid,				// [in] rowset interface to be returned
		ULONG				cPropertySets,		// [in] number of roset property sets asked
		DBPROPSET			*rgPropertySets,	// [in/out] array of rowset property sets
		DBID				**ppTableID,		// [out] returned table ID
		IUnknown			**ppRowset			// [out] pointer to outer interface
	);
	
	// @cmember Initialization Routine
	virtual BOOL Init();
	// @cmember Termination Routine
	virtual BOOL Terminate();

	// {{ TCW_TESTVARS()
	// }} TCW_TESTVARS_END
} ;
// {{ TCW_TESTCASE(TCCreateTableWithConstraints_NoConstraint)
//#define THE_CLASS TCCreateTableWithConstraints_NoConstraint
//BEG_TEST_CASE(TCCreateTableWithConstraints_NoConstraint, TCCreateTable, L"Testcase for ITableDefinitionWithConstraints::AddConstraint used with deferrability setting")
//END_TEST_CASE()
//#undef THE_CLASS
// }} TCW_TESTCASE_END
// }} TCW_TEST_CASE_MAP_END

const WCHAR		TCCreateTableWithConstraints_NoConstraint::m_wszTestCaseName[] = { L"TCCreateTableWithConstraints_NoConstraint" };
const WCHAR		TCCreateTableWithConstraints_NoConstraint::m_wszTestCaseDesc[] = { L"Testcase for ITableDefinitionWithConstraints::CreateTable when no constraints are specified => should expect the same results as for ITableDefinition::CreateTable" };

// {{ TCW_TEST_CASE_MAP(TCCreateTableWithConstraints)
//*-----------------------------------------------------------------------
// @class Testcase for ITableDefinitionWithConstraints::CreateTableWithConstraints when constraints are set
//
class TCCreateTableWithConstraints : public TCITableDefinition { 
private:
	// @cmember Static array of variations
	DECLARE_TEST_CASE_DATA();

public:
	// {{ TCW_DECLARE_FUNCS
	// @cmember Execution Routine
	DECLARE_TEST_CASE_FUNCS(TCCreateTableWithConstraints,TCITableDefinition);
	// }} TCW_DECLARE_FUNCS_END
	
	// @cmember Initialization Routine
	virtual BOOL Init();
	// @cmember Termination Routine
	virtual BOOL Terminate();

	// {{ TCW_TESTVARS()
	// @cmember Create a table and multiple constraint of various types
	int Variation_1();
	// @cmember Table with a unique constraint (on a single column)
	int Variation_2();
	// @cmember Table with a unique constraint (on multiple columns)
	int Variation_3();
	// @cmember Table with a primary key constraint (on a single column)
	int Variation_4();
	// @cmember Table with a primary key constraint (on multiple columns)
	int Variation_5();
	// @cmember Table with a foreign key constraint (single column)
	int Variation_6();
	// @cmember Table with foreign key constraint defined on multiple keys
	int Variation_7();
	// @cmember Table with a simple check constraint
	int Variation_8();
	// @cmember Table with multiple unique constraints defined
	int Variation_9();
	// @cmember Table with unique constraint and foreign key
	int Variation_10();
	// @cmember Table with primary key and check constraint
	int Variation_11();
	// @cmember Deferrable, immediate constraints
	int Variation_12();
	// @cmember Deferred constraints
	int Variation_13();
	// @cmember Abort retain
	int Variation_14();
	// @cmember Abort non retain
	int Variation_15();
	// @cmember Commit retain
	int Variation_16();
	// @cmember Commit non retain
	int Variation_17();
	// }} TCW_TESTVARS_END
} ;
// {{ TCW_TESTCASE(TCCreateTableWithConstraints)
#define THE_CLASS TCCreateTableWithConstraints
BEG_TEST_CASE(TCCreateTableWithConstraints, TCITableDefinition, L"Testcase for ITableDefinitionWithConstraints::CreateTableWithConstraints when constraints are set")
	TEST_VARIATION(1, 		L"Create a table and multiple constraint of various types")
	TEST_VARIATION(2, 		L"Table with a unique constraint (on a single column)")
	TEST_VARIATION(3, 		L"Table with a unique constraint (on multiple columns)")
	TEST_VARIATION(4, 		L"Table with a primary key constraint (on a single column)")
	TEST_VARIATION(5, 		L"Table with a primary key constraint (on multiple columns)")
	TEST_VARIATION(6, 		L"Table with a foreign key constraint (single column)")
	TEST_VARIATION(7, 		L"Table with foreign key constraint defined on multiple keys")
	TEST_VARIATION(8, 		L"Table with a simple check constraint")
	TEST_VARIATION(9, 		L"Table with multiple unique constraints defined")
	TEST_VARIATION(10, 		L"Table with unique constraint and foreign key")
	TEST_VARIATION(11, 		L"Table with primary key and check constraint")
	TEST_VARIATION(12, 		L"Deferrable, immediate constraints")
	TEST_VARIATION(13, 		L"Deferred constraints")
	TEST_VARIATION(14, 		L"Abort retain")
	TEST_VARIATION(15, 		L"Abort non retain")
	TEST_VARIATION(16, 		L"Commit retain")
	TEST_VARIATION(17, 		L"Commit non retain")
END_TEST_CASE()
#undef THE_CLASS
// }} TCW_TESTCASE_END
// }} TCW_TEST_CASE_MAP_END

// {{ TCW_TEST_CASE_MAP(TCCreateTableWithConstraints_Boundary)
//*-----------------------------------------------------------------------
// @class Boundary and NULL testcase for ITableDefinitionWithConstraints::CreateTableWithConstraints
//
class TCCreateTableWithConstraints_Boundary : public TCITableDefinition { 
private:
	// @cmember Static array of variations
	DECLARE_TEST_CASE_DATA();

public:
	// {{ TCW_DECLARE_FUNCS
	// @cmember Execution Routine
	DECLARE_TEST_CASE_FUNCS(TCCreateTableWithConstraints_Boundary,TCITableDefinition);
	// }} TCW_DECLARE_FUNCS_END
	
	// @cmember Initialization Routine
	virtual BOOL Init();
	// @cmember Termination Routine
	virtual BOOL Terminate();

	// {{ TCW_TESTVARS()
	// @cmember 0 < cConstraintDescs and NULL == rgConstraintDescs => E_INVALIDARG
	int Variation_1();
	// @cmember 0 == cConstraintDescs and NULL != rgConstraintDescs => S_OK
	int Variation_2();
	// @cmember pTableID is NULL ppTableID is not NULL => S_OK
	int Variation_3();
	// @cmember Bad DBKIND of a constraint ID
	int Variation_4();
	// @cmember NULL pConstraintID in a constraint
	int Variation_5();
	// @cmember NULL column list in a constraint, column size is not 0 => E_INVALIDARG
	int Variation_6();
	// @cmember Empty list of columns for a unique, primay key or foreign key constraint
	int Variation_7();
	// @cmember Non empty list of columns for a check constraint
	int Variation_8();
	// @cmember Non empty list of foreign keys for a constraint that is not foreign key
	int Variation_9();
	// @cmember 0 < cForeignKeyColumns and NULL == rgForeignKeyColumnList => E_INVALIDARG
	int Variation_10();
	// @cmember Constraint is not foreign key and pReferencedTableID is not NULL
	int Variation_11();
	// @cmember NULL pReferencedTableID for a foreign key constraint (with and without cForeignKeyColumns being 0)
	int Variation_12();
	// @cmember NULL referenced table name for a foreign key constraint
	int Variation_13();
	// @cmember DB_NULLID *pReferencedTableID for a foreign key constraint
	int Variation_14();
	// @cmember Empty string referenced table name for a foreign key constraint
	int Variation_15();
	// @cmember Maximum length referenced table name for a foreign key constraint
	int Variation_16();
	// @cmember Referenced table name longer than allowed for a foreign key constraint
	int Variation_17();
	// @cmember Illegal characters in the referenced table name for a foreign key constraint
	int Variation_18();
	// @cmember Bad constraint type
	int Variation_19();
	// @cmember Inexistent referenced table
	int Variation_20();
	// @cmember Empty string for a column name
	int Variation_21();
	// @cmember Maximum length column name in a constraint
	int Variation_22();
	// @cmember Invalid DBKIND for a column DBID of a constraint
	int Variation_23();
	// @cmember Column ID is DB_NULLID
	int Variation_24();
	// @cmember Inexistent column => DB_E_NOCOLUMN
	int Variation_25();
	// @cmember NULL column name => DB_E_NOCOLUMN
	int Variation_26();
	// @cmember Column name exceeds maximum length name
	int Variation_27();
	// @cmember Invalid column name
	int Variation_28();
	// @cmember Existent table name => DB_E_DUPLICATETABLEID
	int Variation_29();
	// @cmember Same constraint name in 2 constraints => DB_E_DUPLICATECONSTRAINTID
	int Variation_30();
	// @cmember NULL pConstraintID in 2 constraints => S_OK
	int Variation_31();
	// @cmember Try to create table with constraints, but table already exists => DB_E_DUPLICATEDTABLEID
	int Variation_32();
	// }} TCW_TESTVARS_END
} ;

// {{ TCW_TESTCASE(TCCreateTableWithConstraints_Boundary)
#define THE_CLASS TCCreateTableWithConstraints_Boundary
BEG_TEST_CASE(TCCreateTableWithConstraints_Boundary, TCITableDefinition, L"Boundary and NULL testcase for ITableDefinitionWithConstraints::CreateTableWithConstraints")
	TEST_VARIATION(1, 		L"0 < cConstraintDescs and NULL == rgConstraintDescs => E_INVALIDARG")
	TEST_VARIATION(2, 		L"0 == cConstraintDescs and NULL != rgConstraintDescs => S_OK")
	TEST_VARIATION(3, 		L"pTableID is NULL ppTableID is not NULL => S_OK")
	TEST_VARIATION(4, 		L"Bad DBKIND of a constraint ID")
	TEST_VARIATION(5, 		L"NULL pConstraintID in a constraint")
	TEST_VARIATION(6, 		L"NULL column list in a constraint, column size is not 0 => E_INVALIDARG")
	TEST_VARIATION(7, 		L"Empty list of columns for a unique, primay key or foreign key constraint")
	TEST_VARIATION(8, 		L"Non empty list of columns for a check constraint")
	TEST_VARIATION(9, 		L"Non empty list of foreign keys for a constraint that is not foreign key")
	TEST_VARIATION(10, 		L"0 < cForeignKeyColumns and NULL == rgForeignKeyColumnList => E_INVALIDARG")
	TEST_VARIATION(11, 		L"Constraint is not foreign key and pReferencedTableID is not NULL")
	TEST_VARIATION(12, 		L"NULL pReferencedTableID for a foreign key constraint (with and without cForeignKeyColumns being 0)")
	TEST_VARIATION(13, 		L"NULL referenced table name for a foreign key constraint")
	TEST_VARIATION(14, 		L"DB_NULLID *pReferencedTableID for a foreign key constraint")
	TEST_VARIATION(15, 		L"Empty string referenced table name for a foreign key constraint")
	TEST_VARIATION(16, 		L"Maximum length referenced table name for a foreign key constraint")
	TEST_VARIATION(17, 		L"Referenced table name longer than allowed for a foreign key constraint")
	TEST_VARIATION(18, 		L"Illegal characters in the referenced table name for a foreign key constraint")
	TEST_VARIATION(19, 		L"Bad constraint type")
	TEST_VARIATION(20, 		L"Inexistent referenced table")
	TEST_VARIATION(21, 		L"Empty string for a column name")
	TEST_VARIATION(22, 		L"Maximum length column name in a constraint")
	TEST_VARIATION(23, 		L"Invalid DBKIND for a column DBID of a constraint")
	TEST_VARIATION(24, 		L"Column ID is DB_NULLID")
	TEST_VARIATION(25, 		L"Inexistent column => DB_E_NOCOLUMN")
	TEST_VARIATION(26, 		L"NULL column name => DB_E_NOCOLUMN")
	TEST_VARIATION(27, 		L"Column name exceeds maximum length name")
	TEST_VARIATION(28, 		L"Invalid column name")
	TEST_VARIATION(29, 		L"Existent table name => DB_E_DUPLICATETABLEID")
	TEST_VARIATION(30, 		L"Same constraint name in 2 constraints => DB_E_DUPLICATECONSTRAINTID")
	TEST_VARIATION(31, 		L"NULL pConstraintID in 2 constraints => S_OK")
	TEST_VARIATION(32, 		L"Try to create table with constraints, but table already exists => DB_E_DUPLICATEDTABLEID")
END_TEST_CASE()
#undef THE_CLASS
// }} TCW_TESTCASE_END
// }} TCW_TEST_CASE_MAP_END

// {{ TCW_TEST_CASE_MAP(TCDropConstraint)
//*-----------------------------------------------------------------------
// @class Testcase for ITableDefinitionWithConstraints::DropConstraint
//
class TCDropConstraint : public TCITableDefinition { 
private:
	// @cmember Static array of variations
	DECLARE_TEST_CASE_DATA();

public:
	// {{ TCW_DECLARE_FUNCS
	// @cmember Execution Routine
	DECLARE_TEST_CASE_FUNCS(TCDropConstraint,TCITableDefinition);
	// }} TCW_DECLARE_FUNCS_END
	
	// @cmember Initialization Routine
	virtual BOOL Init();
	// @cmember Termination Routine
	virtual BOOL Terminate();

	// {{ TCW_TESTVARS()
	// @cmember pTableID is NULL => E_INVALIDARG
	int Variation_1();
	// @cmember pTableID.uName.pwszName is NULL => DB_E_BADTABLEID
	int Variation_2();
	// @cmember Table name is empty => DB_E_BADTABLEID
	int Variation_3();
	// @cmember Table name is not the one on which the column was created
	int Variation_4();
	// @cmember Inexistent table name => DB_E_NOTABLE
	int Variation_5();
	// @cmember Maximum table name => S_OK
	int Variation_6();
	// @cmember Invalid characters in table's name => DB_E_BADTABLEID
	int Variation_7();
	// @cmember pConstraintID is NUL => E_INVALIDARG
	int Variation_8();
	// @cmember *pConstraintID is DB_NULLID => DB_E_NOCONSTRAINT
	int Variation_9();
	// @cmember Invalid DBKIND in the constraint name => DB_E_NOCONSTRAINT
	int Variation_10();
	// @cmember NULL constraint name => DB_E_NOCONSTRAINT
	int Variation_11();
	// @cmember Constraint name is empty string => DB_E_NOCONSTRAINT
	int Variation_12();
	// @cmember Inexistent constraint name => DB_E_NOCONSTRAINT
	int Variation_13();
	// @cmember Drop a constraint twice
	int Variation_14();
	// @cmember Drop a unique constraint
	int Variation_15();
	// @cmember Drop a primary key constraint
	int Variation_16();
	// @cmember Drop a foreign key constraint
	int Variation_17();
	// @cmember Drop a check constraint
	int Variation_18();
	// @cmember Create several constraints, drop a single constraint
	int Variation_19();
	// @cmember Drop a unique constraint in the referenced table, after the foreign key constraint was added
	int Variation_20();
	// @cmember Try to drop a unique constraint while a rowset is opened on the table => DB_E_TABLEINUSE
	int Variation_21();
	// @cmember *pTableID is DB_NULLID => DB_E_BADTABLEID
	int Variation_22();
	// @cmember Invalid DBKIND in pTableID => DB_E_BADTABLEID
	int Variation_23();
	// @cmember Try to drop a check constraint while a rowset is opened on the table => DB_E_TABLEINUSE
	int Variation_24();
	// @cmember Try to drop a pk constraint while a rowset is opened on the table => DB_E_TABLEINUSE
	int Variation_25();
	// @cmember Try to drop a fk constraint while a rowset is opened on the table => DB_E_TABLEINUSE
	int Variation_26();
	// @cmember Both pTableID and pConstraintID are NULL => E_INVALIDARG
	int Variation_27();
	// @cmember Abort retain
	int Variation_28();
	// @cmember Abort non retain
	int Variation_29();
	// @cmember Commit retain
	int Variation_30();
	// @cmember Commit non retain
	int Variation_31();
	// }} TCW_TESTVARS_END
} ;
// {{ TCW_TESTCASE(TCDropConstraint)
#define THE_CLASS TCDropConstraint
BEG_TEST_CASE(TCDropConstraint, TCITableDefinition, L"Testcase for ITableDefinitionWithConstraints::DropConstraint")
	TEST_VARIATION(1, 		L"pTableID is NULL => E_INVALIDARG")
	TEST_VARIATION(2, 		L"pTableID.uName.pwszName is NULL => DB_E_BADTABLEID")
	TEST_VARIATION(3, 		L"Table name is empty => DB_E_BADTABLEID")
	TEST_VARIATION(4, 		L"Table name is not the one on which the column was created")
	TEST_VARIATION(5, 		L"Inexistent table name => DB_E_NOTABLE")
	TEST_VARIATION(6, 		L"Maximum table name => S_OK")
	TEST_VARIATION(7, 		L"Invalid characters in table's name => DB_E_BADTABLEID")
	TEST_VARIATION(8, 		L"pConstraintID is NUL => E_INVALIDARG")
	TEST_VARIATION(9, 		L"*pConstraintID is DB_NULLID => DB_E_NOCONSTRAINT")
	TEST_VARIATION(10, 		L"Invalid DBKIND in the constraint name => DB_E_NOCONSTRAINT")
	TEST_VARIATION(11, 		L"NULL constraint name => DB_E_NOCONSTRAINT")
	TEST_VARIATION(12, 		L"Constraint name is empty string => DB_E_NOCONSTRAINT")
	TEST_VARIATION(13, 		L"Inexistent constraint name => DB_E_NOCONSTRAINT")
	TEST_VARIATION(14, 		L"Drop a constraint twice")
	TEST_VARIATION(15, 		L"Drop a unique constraint")
	TEST_VARIATION(16, 		L"Drop a primary key constraint")
	TEST_VARIATION(17, 		L"Drop a foreign key constraint")
	TEST_VARIATION(18, 		L"Drop a check constraint")
	TEST_VARIATION(19, 		L"Create several constraints, drop a single constraint")
	TEST_VARIATION(20, 		L"Drop a unique constraint in the referenced table, after the foreign key constraint was added")
	TEST_VARIATION(21, 		L"Try to drop a unique constraint while a rowset is opened on the table => DB_E_TABLEINUSE")
	TEST_VARIATION(22, 		L"*pTableID is DB_NULLID => DB_E_BADTABLEID")
	TEST_VARIATION(23, 		L"Invalid DBKIND in pTableID => DB_E_BADTABLEID")
	TEST_VARIATION(24, 		L"Try to drop a check constraint while a rowset is opened on the table => DB_E_TABLEINUSE")
	TEST_VARIATION(25, 		L"Try to drop a pk constraint while a rowset is opened on the table => DB_E_TABLEINUSE")
	TEST_VARIATION(26, 		L"Try to drop a fk constraint while a rowset is opened on the table => DB_E_TABLEINUSE")
	TEST_VARIATION(27, 		L"Both pTableID and pConstraintID are NULL => E_INVALIDARG")
	TEST_VARIATION(28, 		L"Abort retain")
	TEST_VARIATION(29, 		L"Abort non retain")
	TEST_VARIATION(30, 		L"Commit retain")
	TEST_VARIATION(31, 		L"Commit non retain")
END_TEST_CASE()
#undef THE_CLASS
// }} TCW_TESTCASE_END
// }} TCW_TEST_CASE_MAP_END

// {{ TCW_TEST_CASE_MAP(TCAddConstraint_Multithreading)
//*-----------------------------------------------------------------------
// @class Testcase for ITableDefinitionWithConstraints::AddConstraint used in multithreaded calls
//
class TCAddConstraint_Multithreading : public TCITableDefinition { 
private:
	// @cmember Static array of variations
	DECLARE_TEST_CASE_DATA();

	DBID				**m_prgTableID;
	DBCONSTRAINTDESC	*m_rgConstraintDesc;

public:
	// {{ TCW_DECLARE_FUNCS
	// @cmember Execution Routine
	DECLARE_TEST_CASE_FUNCS(TCAddConstraint_Multithreading,TCITableDefinition);
	// }} TCW_DECLARE_FUNCS_END
	
	// @cmember Initialization Routine
	virtual BOOL Init();
	// @cmember Termination Routine
	virtual BOOL Terminate();

	// {{ TCW_TESTVARS()
	// @cmember Each thread creates a different constraint
	int Variation_1();
	// @cmember Some of the threads try to create the same constraint name
	int Variation_2();
	// @cmember Unique constraints with disjoint columns
	int Variation_3();
	// @cmember Unique constraints with overlapping columns
	int Variation_4();
	// @cmember All constraint IDs are generated by the provider
	int Variation_5();
	// }} TCW_TESTVARS_END

	unsigned MyThreadProc(ULONG i);
} ;
// {{ TCW_TESTCASE(TCAddConstraint_Multithreading)
#define THE_CLASS TCAddConstraint_Multithreading
BEG_TEST_CASE(TCAddConstraint_Multithreading, TCITableDefinition, L"Testcase for ITableDefinitionWithConstraints::AddConstraint used in multithreaded calls")
	TEST_VARIATION(1, 		L"Each thread creates a different constraint")
	TEST_VARIATION(2, 		L"Some of the threads try to create the same constraint name")
	TEST_VARIATION(3, 		L"Unique constraints with disjoint columns")
	TEST_VARIATION(4, 		L"Unique constraints with overlapping columns")
	TEST_VARIATION(5, 		L"All constraint IDs are generated by the provider")
END_TEST_CASE()
#undef THE_CLASS
// }} TCW_TESTCASE_END
// }} TCW_TEST_CASE_MAP_END

// {{ TCW_TEST_CASE_MAP(TCDropConstraint_Multithreading)
//*-----------------------------------------------------------------------
// @class Multithreading test case for ITableDefinitionWithConstraints::DropConstraints
//
class TCDropConstraint_Multithreading : public TCITableDefinition { 
private:
	// @cmember Static array of variations
	DECLARE_TEST_CASE_DATA();

	DBID		**m_prgTableID;
	DBID		**m_prgConstraintID;

public:
	// {{ TCW_DECLARE_FUNCS
	// @cmember Execution Routine
	DECLARE_TEST_CASE_FUNCS(TCDropConstraint_Multithreading,TCITableDefinition);
	// }} TCW_DECLARE_FUNCS_END
	
	// @cmember Initialization Routine
	virtual BOOL Init();
	// @cmember Termination Routine
	virtual BOOL Terminate();

	// {{ TCW_TESTVARS()
	// @cmember Each thread drops a different constraint => all S_OK
	int Variation_1();
	// @cmember Some threads try to drop the same constraint => S_OK and DB_E_NOCONSTRAINT
	int Variation_2();
	// }} TCW_TESTVARS_END

	unsigned MyThreadProc(ULONG i);
} ;
// {{ TCW_TESTCASE(TCDropConstraint_Multithreading)
#define THE_CLASS TCDropConstraint_Multithreading
BEG_TEST_CASE(TCDropConstraint_Multithreading, TCITableDefinition, L"Multithreading test case for ITableDefinitionWithConstraints::DropConstraints")
	TEST_VARIATION(1, 		L"Each thread drops a different constraint => all S_OK")
	TEST_VARIATION(2, 		L"Some threads try to drop the same constraint => S_OK and DB_E_NOCONSTRAINT")
END_TEST_CASE()
#undef THE_CLASS
// }} TCW_TESTCASE_END
// }} TCW_TEST_CASE_MAP_END

// {{ TCW_TEST_CASE_MAP(TCCreateTableWithConstraints_Multithreading)
//*-----------------------------------------------------------------------
// @class Multithreading test case for ITableDefinitionWithConstraints::CreateTableWithConstraints
//
class TCCreateTableWithConstraints_Multithreading : public TCITableDefinition { 
private:
	// @cmember Static array of variations
	DECLARE_TEST_CASE_DATA();

	CCTWCThreadParam	*m_rgThreadParams;

public:
	// {{ TCW_DECLARE_FUNCS
	// @cmember Execution Routine
	DECLARE_TEST_CASE_FUNCS(TCCreateTableWithConstraints_Multithreading,TCITableDefinition);
	// }} TCW_DECLARE_FUNCS_END
	
	// @cmember Initialization Routine
	virtual BOOL Init();
	// @cmember Termination Routine
	virtual BOOL Terminate();

	// {{ TCW_TESTVARS()
	// @cmember Each thread builds different table => all S_OK
	int Variation_1();
	// @cmember Some threads build the same table => S_OK and DB_E_DUPLICATETABLEID
	int Variation_2();
	// }} TCW_TESTVARS_END

	unsigned MyThreadProc(ULONG i);
} ;
// {{ TCW_TESTCASE(TCCreateTableWithConstraints_Multithreading)
#define THE_CLASS TCCreateTableWithConstraints_Multithreading
BEG_TEST_CASE(TCCreateTableWithConstraints_Multithreading, TCITableDefinition, L"Multithreading test case for ITableDefinitionWithConstraints::CreateTableWithConstraints")
	TEST_VARIATION(1, 		L"Each thread builds different table => all S_OK")
	TEST_VARIATION(2, 		L"Some threads build the same table => S_OK and DB_E_DUPLICATETABLEID")
END_TEST_CASE()
#undef THE_CLASS
// }} TCW_TESTCASE_END
// }} TCW_TEST_CASE_MAP_END

// }} END_DECLARE_TEST_CASES()


// {{ TCW_TESTMODULE(ThisModule)
TEST_MODULE(18, ThisModule, gwszModuleDescrip)
	TEST_CASE(1, TCAddColumn)
	TEST_CASE(2, TCDropColumn)
	TEST_CASE(3, TCDropTable)
	TEST_CASE(4, TCCreateTable)
	TEST_CASE(5, RODataSource)
	TEST_CASE(6, TCAddConstraint_Boundary)
	TEST_CASE(7, TCAddConstraint_UNIQUE)
	TEST_CASE(8, TCAddConstraint_PRIMARYKEY)
	TEST_CASE(9, TCAddConstraint_FOREIGNKEY)
	TEST_CASE(10, TCAddConstraint_CHECK)
	TEST_CASE(11, TCAddConstraint_Deferrability)
	TEST_CASE(12, TCCreateTableWithConstraints_NoConstraint)
	TEST_CASE(13, TCCreateTableWithConstraints)
	TEST_CASE(14, TCCreateTableWithConstraints_Boundary)
	TEST_CASE(15, TCDropConstraint)
	TEST_CASE(16, TCAddConstraint_Multithreading)
	TEST_CASE(17, TCDropConstraint_Multithreading)
	TEST_CASE(18, TCCreateTableWithConstraints_Multithreading)
END_TEST_MODULE()
// }} TCW_TESTMODULE_END


class CTransactionAdapter {
	public:
							CTransactionAdapter() {}
							~CTransactionAdapter() {}

		virtual BOOL		BeforeTransaction() = 0;
		virtual HRESULT		InsideTransactionScope() = 0;
		virtual HRESULT		InsideTransactionOnDDLLock() = 0; 
		virtual BOOL		CheckCompletion() = 0; 
		virtual BOOL		CheckRollBack()  = 0; 
}; //class CTransactionAdapter


class CAddConstraintTxnAdapter: public CTransactionAdapter {
	protected:
		TCITableDefinition	*m_pTCITableDefinition;
		CTable				m_Table;
		CConstraints		*m_pConstraints;
		CConsDesc			*m_pCons;
		// m_TransactedTable will be created inside the transaction
		CTable				m_TransactedTable;	
		// constraint on transacted table
		CConsDesc			*m_pTransactedTableCons;
		CConstraints		*m_pTxnConstraints;

	public:
							CAddConstraintTxnAdapter(TCITableDefinition *pTCITableDefinition) : 
								CTransactionAdapter(), 
								m_pTCITableDefinition(pTCITableDefinition), 
								m_pConstraints(NULL), m_pCons(NULL),
								m_Table(g_pIOpenRowset, (LPWSTR)gwszModuleName),
								m_TransactedTable(g_pIOpenRowset, (LPWSTR)gwszModuleName),
								m_pTransactedTableCons(NULL),
								m_pTxnConstraints(NULL)
								{}
							~CAddConstraintTxnAdapter() {
								m_Table.DropTable();
								m_TransactedTable.DropTable();
								delete m_pConstraints;
								delete m_pCons;
								delete m_pTransactedTableCons;
								delete m_pTxnConstraints;
							}

		
		TCITableDefinition	*pTCITableDefinition() {return m_pTCITableDefinition;}
		virtual BOOL		BeforeTransaction();
		
		virtual HRESULT		InsideTransactionScope() {
								return m_pTCITableDefinition->AddConstraintAndCheck(
									m_pTCITableDefinition->pITDWC(), 
									&m_Table.GetTableID(), *m_pCons);								
		}
		virtual HRESULT		InsideTransactionOnDDLLock() {
								return m_pTCITableDefinition->pITDWC()->AddConstraint(
									&m_Table.GetTableID(), *m_pCons);
		}

		virtual BOOL		CheckCompletion() {
								TBEGIN
								BOOL	fTableExisted;
								ASSERT(m_pCons);
								CHECK(m_pConstraints->CheckAddConstraints(1, *m_pCons), S_OK);

								// transacted table exists
								ASSERT(m_pTransactedTableCons);
								CHECK(m_TransactedTable.DoesTableExist(&m_TransactedTable.GetTableID(), &fTableExisted), S_OK);
								COMPARE(fTableExisted, TRUE);
								CHECK(m_pTxnConstraints->CheckAddConstraints(1, *m_pTransactedTableCons), S_OK);
								TRETURN
		}
		virtual BOOL		CheckRollBack() {
								TBEGIN
								BOOL	fTableExisted;

								ASSERT(m_pCons);
								CHECK(m_pConstraints->AreConstraintsPreserved(), S_OK);
								
								// transacted table does not exist
								ASSERT(m_pTransactedTableCons);
								CHECK(m_TransactedTable.DoesTableExist(&m_TransactedTable.GetTableID(), &fTableExisted), S_OK);
								COMPARE(fTableExisted, FALSE);
								CHECK(m_pTxnConstraints->AreConstraintsPreserved(), S_OK);
								TRETURN
		}
}; //class CAddConstraintTxnAdapter



class CAddUniqueConsTxnAdapter: public CAddConstraintTxnAdapter {
	public:
							CAddUniqueConsTxnAdapter(TCITableDefinition *pTCITableDefinition):
								CAddConstraintTxnAdapter(pTCITableDefinition) {}
							~CAddUniqueConsTxnAdapter() {
							}

		virtual BOOL		BeforeTransaction();
		virtual HRESULT		InsideTransactionScope();
		virtual HRESULT		InsideTransactionOnDDLLock();
		virtual BOOL		CheckCompletion();
		virtual BOOL		CheckRollBack();
}; //class CAddUniqueConsTxnAdapter



class CAddPrimaryKeyConsTxnAdapter: public CAddUniqueConsTxnAdapter {
	public:
							CAddPrimaryKeyConsTxnAdapter(TCITableDefinition *pTCITableDefinition):
								CAddUniqueConsTxnAdapter(pTCITableDefinition)
								{}
							~CAddPrimaryKeyConsTxnAdapter() {
							}

		virtual BOOL		BeforeTransaction();
}; //class CAddPrimaryKeyConsTxnAdapter



class CAddFKConsTxnAdapter: public CAddConstraintTxnAdapter {
	private:
		CTable				m_ReferencedTable;

	public:
							CAddFKConsTxnAdapter(TCITableDefinition *pTCITableDefinition):
								CAddConstraintTxnAdapter(pTCITableDefinition),
								m_ReferencedTable(g_pIOpenRowset, (LPWSTR)gwszModuleName)
								{}
							~CAddFKConsTxnAdapter() {
								m_Table.DropTable();
								m_TransactedTable.DropTable();
								m_ReferencedTable.DropTable();
							}

		virtual BOOL		BeforeTransaction();
		virtual HRESULT		InsideTransactionScope();
		virtual HRESULT		InsideTransactionOnDDLLock();
		virtual BOOL		CheckCompletion();
		virtual BOOL		CheckRollBack();
}; //class CAddFKConsTxnAdapter



class CAddCheckConsTxnAdapter: public CAddConstraintTxnAdapter {
	public:
							CAddCheckConsTxnAdapter(TCITableDefinition *pTCITableDefinition):
								CAddConstraintTxnAdapter(pTCITableDefinition)
								{}
							~CAddCheckConsTxnAdapter() {}

		virtual BOOL		BeforeTransaction();
		virtual HRESULT		InsideTransactionScope();
		virtual HRESULT		InsideTransactionOnDDLLock();
		virtual BOOL		CheckCompletion();
		virtual BOOL		CheckRollBack();
}; //class CAddCheckConsTxnAdapter



class CCreateTableWithConsTxnAdapter: public CTransactionAdapter {
	protected:
		TCITableDefinition	*m_pTCITableDefinition;
		CTable				m_Table;
		CConstraints		*m_pConstraints;
		CConsDescArray		m_ConsDescArray;
		// m_TransactedTable will be created inside the transaction
		CTable				m_RefTable;	
		DBORDINAL			m_cColumnDesc;
		DBCOLUMNDESC		*m_rgColumnDesc;

	public:
							CCreateTableWithConsTxnAdapter(TCITableDefinition *pTCITableDefinition) : 
								CTransactionAdapter(), 
								m_pTCITableDefinition(pTCITableDefinition), 
								m_pConstraints(NULL), 
								m_Table(g_pIOpenRowset, (LPWSTR)gwszModuleName),
								m_RefTable(g_pIOpenRowset, (LPWSTR)gwszModuleName),
								m_cColumnDesc(0), m_rgColumnDesc(NULL)
								{}
							~CCreateTableWithConsTxnAdapter() {
								m_Table.DropTable();
								m_RefTable.DropTable();
								delete m_pConstraints;
								m_pConstraints = NULL;
								ReleaseColumnDesc(m_rgColumnDesc, m_cColumnDesc);
							}

		
		TCITableDefinition	*pTCITableDefinition() {return m_pTCITableDefinition;}
		virtual BOOL		BeforeTransaction();
		
		virtual HRESULT		InsideTransactionScope() {
								return m_pTCITableDefinition->CreateAndCheckTableWithConstraints(
											m_pTCITableDefinition->pITDWC(),
											NULL,
											&m_Table.GetTableID(),
											m_cColumnDesc,
											m_rgColumnDesc,
											m_ConsDescArray,	
											m_ConsDescArray,
											IID_NULL,	
											0, NULL,
											NULL,
											NULL);
		}
		virtual HRESULT		InsideTransactionOnDDLLock() {
								return m_pTCITableDefinition->pITDWC()->CreateTableWithConstraints(
									NULL, &m_Table.GetTableID(), 
											m_cColumnDesc,
											m_rgColumnDesc,
											m_ConsDescArray,	
											m_ConsDescArray,
											IID_NULL,	
											0, NULL,
											NULL,
											NULL);
		}

		virtual BOOL		CheckCompletion() {
								TBEGIN
								BOOL	fTableExisted;

								// check constraints were added
								CHECK(m_pConstraints->CheckAddConstraints(m_ConsDescArray, m_ConsDescArray), S_OK);

								// transacted table exists
								CHECK(m_Table.DoesTableExist(&m_Table.GetTableID(), &fTableExisted), S_OK);
								COMPARE(fTableExisted, TRUE);
								TRETURN
		}
		virtual BOOL		CheckRollBack() {
								TBEGIN
								BOOL	fTableExisted;

								CHECK(m_pConstraints->AreConstraintsPreserved(), S_OK);							
								// transacted table does not exist
								CHECK(m_Table.DoesTableExist(&m_Table.GetTableID(), &fTableExisted), S_OK);
								COMPARE(fTableExisted, FALSE);
								TRETURN
		}
}; //class CCreateTableWithConsTxnAdapter



class CDropConsTxnAdapter: public CTransactionAdapter {
	protected:
		TCITableDefinition	*m_pTCITableDefinition;
		CTable				m_Table;
		CTable				m_RefTable;
		CConstraints		*m_pConstraints;
		CPrimaryKeyCons		*m_pPKCons;
		CForeignKeyCons		*m_pFKCons;
		CUniqueCons			*m_pUniqueCons;
		CCheckCons			*m_pCheckCons;

	public:
							CDropConsTxnAdapter(TCITableDefinition *pTCITableDefinition) : 
								CTransactionAdapter(), 
								m_pTCITableDefinition(pTCITableDefinition), 
								m_pConstraints(NULL),
								m_Table(g_pIOpenRowset, (LPWSTR)gwszModuleName),
								m_RefTable(g_pIOpenRowset, (LPWSTR)gwszModuleName),
								m_pPKCons(NULL), m_pFKCons(NULL), m_pUniqueCons(NULL), m_pCheckCons(NULL)
								{}
							~CDropConsTxnAdapter() {
								m_Table.DropTable();
								m_RefTable.DropTable();
								delete m_pConstraints;
								delete m_pPKCons;
								delete m_pFKCons;
								delete m_pUniqueCons;
								delete m_pCheckCons;
							}

		
		TCITableDefinition	*pTCITableDefinition() {return m_pTCITableDefinition;}
		virtual BOOL		BeforeTransaction();
		
		virtual HRESULT		InsideTransactionScope() {
								HRESULT		hr = S_OK;
								HRESULT		hres;

								hres = m_pTCITableDefinition->DropConstraintAndCheck(
									m_pTCITableDefinition->pITDWC(), 
									&m_Table.GetTableID(), *m_pPKCons);								
								hr = (S_OK == hr)? hres: hr;

								hres = m_pTCITableDefinition->DropConstraintAndCheck(
									m_pTCITableDefinition->pITDWC(), 
									&m_Table.GetTableID(), *m_pFKCons);								
								hr = (S_OK == hr)? hres: hr;

								hres = m_pTCITableDefinition->DropConstraintAndCheck(
									m_pTCITableDefinition->pITDWC(), 
									&m_Table.GetTableID(), *m_pUniqueCons);								
								hr = (S_OK == hr)? hres: hr;

								hres = m_pTCITableDefinition->DropConstraintAndCheck(
									m_pTCITableDefinition->pITDWC(), 
									&m_Table.GetTableID(), *m_pCheckCons);								
								hr = (S_OK == hr)? hres: hr;

								return hr;
		}
		virtual HRESULT		InsideTransactionOnDDLLock() {
								HRESULT		hr = S_OK;
								HRESULT		hres;

								hres = m_pTCITableDefinition->pITDWC()->DropConstraint(
									&m_Table.GetTableID(), *m_pPKCons);								
								hr = (S_OK == hr)? hres: hr;

								hres = m_pTCITableDefinition->pITDWC()->DropConstraint(
									&m_Table.GetTableID(), *m_pFKCons);								
								hr = (S_OK == hr)? hres: hr;

								hres = m_pTCITableDefinition->pITDWC()->DropConstraint(
									&m_Table.GetTableID(), *m_pUniqueCons);								
								hr = (S_OK == hr)? hres: hr;

								hres = m_pTCITableDefinition->pITDWC()->DropConstraint(
									&m_Table.GetTableID(), *m_pCheckCons);								
								hr = (S_OK == hr)? hres: hr;

								return hr;
		}

		virtual BOOL		CheckCompletion() {
								TBEGIN

								ASSERT(m_pPKCons);
								ASSERT(m_pFKCons);
								ASSERT(m_pUniqueCons);
								ASSERT(m_pCheckCons);
								CHECK(m_pConstraints->CheckDropConstraint(*m_pPKCons), S_OK);
								CHECK(m_pConstraints->CheckDropConstraint(*m_pFKCons), S_OK);
								CHECK(m_pConstraints->CheckDropConstraint(*m_pUniqueCons), S_OK);
								CHECK(m_pConstraints->CheckDropConstraint(*m_pCheckCons), S_OK);
								TRETURN
		}
		virtual BOOL		CheckRollBack() {
								TBEGIN
								ASSERT(m_pPKCons);
								ASSERT(m_pFKCons);
								ASSERT(m_pUniqueCons);
								ASSERT(m_pCheckCons);
								CHECK(m_pConstraints->AreConstraintsPreserved(), S_OK);							
								TRETURN
		}
}; //class CDropConsTxnAdapter




class CTransactionLocal {
	protected:
		CLightDataSource			m_DataSource;
		CLightSession				m_Session;
		LONG					m_lSupportedTxnDDL;
		CTransactionAdapter		*m_pTAdapter;

	public:
							CTransactionLocal(
							) {
								m_pTAdapter = NULL; 
								m_lSupportedTxnDDL = DBPROPVAL_TC_NONE;
							}

							~CTransactionLocal() {		}
		
		virtual HRESULT		StartTransaction(
								IUnknown				*pISessionUnknown,
								// arguments for ITransactionLocal::StartTransaction
								ISOLEVEL                isoLevel,
								ULONG                   isoFlags,
								ITransactionOptions		*pOtherOptions						
							);
		virtual HRESULT		Abort(
								BOID *   pboidReason,
								BOOL     fRetaining,
								BOOL     fAsync
								) {
									return ((ITransactionLocal*)m_Session)->Abort(pboidReason, fRetaining, fAsync);
		}
		virtual HRESULT		Commit(
								BOOL    fRetaining,
								DWORD   grfTC,
								DWORD   grfRM
								) {
									return ((ITransactionLocal*)m_Session)->Commit(fRetaining, grfTC, grfRM);
		}

		virtual BOOL		DoTransactionTest(
								IUnknown				*pISessionUnknown,
								CTransactionAdapter		*pTAdapter,
								// arguments for ITransactionLocal::Abort / Commit
								BOOL					fDDL,			// whether or not this is a DDL call
   								BOOL					fAbortCommit,	// whether to abort or commit
								BOOL					fRetaining		// if it's retaining or not
							);

}; //CTransactionLocal





//---------------------------------------------------------------------
//
// @cmember Initialize the TCIDefinition data members
//---------------------------------------------------------------------
BOOL TCITableDefinition::Init()
{
	m_pITDWC			= NULL;
	m_pITableDefinition	= NULL;
	m_nTables			= 0;

	InitializeCriticalSection(&m_CriticalSection);
	if(CSessionObject::Init())
	{
		SetDataSourceObject(m_pThisTestModule->m_pIUnknown);
		SetDBSession(m_pThisTestModule->m_pIUnknown2);
		// select ITableDefinition as standard table creation method
		GetModInfo()->UseITableDefinition(TRUE);	
		GetProviderTypes();
		GetLiteralInfo();
		m_nTables = GetNoOfTables();
		m_pTable = new CTable(m_pThisTestModule->m_pIUnknown2, (LPWSTR)gwszModuleName);

		// check for ITableDefinition
		if (!(m_hr=VerifyInterface(m_pIOpenRowset, IID_ITableDefinition, SESSION_INTERFACE, (IUnknown**)&m_pITableDefinition)))
			return FALSE;
		
		m_pIOpenRowset->QueryInterface(IID_ITableDefinitionWithConstraints, (void**)&m_pITDWC);
		
		if (m_pITDWC)
		{
			// find out what values of matching types are supported for foreign keys
			DBORDINAL	rgCol[] = {1};
			CTable		Table(m_pThisTestModule->m_pIUnknown2, (LPWSTR)gwszModuleName);
			CTable		Table2(m_pThisTestModule->m_pIUnknown2, (LPWSTR)gwszModuleName);
			HRESULT		hr;

			TESTC_(Table.CreateTable(0, 1), S_OK);
			CHECK(Table.AddInfoFromColumnsSchemaRowset(m_pITableDefinition), S_OK);
			TESTC_(Table2.CreateTable(0, 1), S_OK);
			CHECK(Table2.AddInfoFromColumnsSchemaRowset(m_pITableDefinition), S_OK);
	
			m_SupportedMatchType = DBMATCHTYPE_NONE;
			TEST2C_(hr = AddForeignKeyConstraint(&Table, NUMELEM(rgCol), rgCol, &Table2, NUMELEM(rgCol), rgCol, 
				m_SupportedMatchType), S_OK, DB_E_BADMATCHTYPE);

			if (S_OK != hr)
			{
				m_SupportedMatchType = DBMATCHTYPE_PARTIAL;
				TEST2C_(hr = AddForeignKeyConstraint(&Table, NUMELEM(rgCol), rgCol, &Table2, NUMELEM(rgCol), rgCol, 
					m_SupportedMatchType), S_OK, DB_E_BADMATCHTYPE);

				if (S_OK != hr)
				{
					m_SupportedMatchType = DBMATCHTYPE_FULL;
					TESTC_(hr = AddForeignKeyConstraint(&Table, NUMELEM(rgCol), rgCol, &Table2, NUMELEM(rgCol), rgCol, 
						m_SupportedMatchType), S_OK);
				}
			}

		CLEANUP:
			Table.DropTable();
			Table2.DropTable();
		}
		return TRUE;
	}
	return FALSE;
}




//---------------------------------------------------------------------
//
// @cmember constructor
//---------------------------------------------------------------------
TCITableDefinition::TCITableDefinition(WCHAR *wstrTestCaseName):CSessionObject(wstrTestCaseName)
{
	m_fIsIDBInfo			= NULL;
	m_pwszInvalidTableChars	= NULL;
	m_pwszInvalidColChars	= NULL;
	m_pITableDefinition		= NULL;
	m_rgColumnDesc			= NULL;
	m_cColumnDesc			= 0;
} //TCITableDefinition::TCITableDefinition




//-------------------------------------------------------------------------
//
// @cmember Compare two column in the identical position
//------------------------------------------------------------------------- 
BOOL TCITableDefinition::AreColEqual
(
	   DBCOLUMNDESC	*oldCD, 
	   DBCOLUMNDESC *newCD
)
{
	// when this function is called, it is supposed that m_HasAuto... were set by GetTableColumnInfo
	// and unmodified ever since
	ULONG		cPropSet, cProp;
	BOOL		fResult = FALSE;
	DBPROPSET	*pNewPropSet = NULL;
	DBPROPSET	*pOldPropSet = NULL;
	DBPROP		*pNewProp = NULL;
	DBPROP		*pOldProp = NULL;

	// compare everything in the stru
	ASSERT(oldCD->pTypeInfo == newCD->pTypeInfo);
	TESTC(oldCD->pTypeInfo == newCD->pTypeInfo);
	TESTC(oldCD->ulColumnSize == newCD->ulColumnSize);
	TESTC(oldCD->wType == newCD->wType);
	TESTC(!IsNumericType(oldCD->wType) || oldCD->bPrecision == newCD->bPrecision);
	TESTC(	(oldCD->wType != DBTYPE_NUMERIC && oldCD->wType != DBTYPE_DECIMAL) 
			|| oldCD->bScale == newCD->bScale);
	TESTC(m_hr = CompareDBID(oldCD->dbcid, newCD->dbcid, m_pIDBInitialize));

	// invalidated for the time being
	// if the CLSID are to be compared for the lists, then a GUID object has to be allocated and mentained; 
	// during the life of each ColumnDescriptor array
	// if a pointer to m_gTypeGUID of a column is stored we'll have troubles as soon as the value of the column changes
	//if (m_pTable->GetHasCLSID() && !CHECK(oldCD->pclsid == newCD->pclsid, TRUE))
	//	return FALSE;
	
	// compare the properties
	TESTC(oldCD->cPropertySets == newCD->cPropertySets);

	for (cPropSet=0; cPropSet<oldCD->cPropertySets; cPropSet++)
	{
		pOldPropSet = &(oldCD->rgPropertySets[cPropSet]);
		pNewPropSet = &(newCD->rgPropertySets[cPropSet]);

		// compare the props in that prop set
		TESTC(pOldPropSet->guidPropertySet == pNewPropSet->guidPropertySet);
		TESTC(pOldPropSet->cProperties == pNewPropSet->cProperties);

		for (cProp = 0; cProp < pOldPropSet->cProperties; cProp++)
		{
			pOldProp = &(pOldPropSet->rgProperties[cProp]);
			pNewProp = &(pNewPropSet->rgProperties[cProp]);

			// there are no info for some of the properties
			if (	((pNewProp->dwPropertyID == DBPROP_COL_AUTOINCREMENT) && !m_pTable->GetHasAuto()) 
				||	((pNewProp->dwPropertyID == DBPROP_COL_DEFAULT) && !m_pTable->GetHasDefault()) 
				||	((pNewProp->dwPropertyID == DBPROP_COL_UNIQUE) && !m_pTable->GetHasUnique())
			   )
				continue;

			TESTC(pOldProp->dwPropertyID ==	pNewProp->dwPropertyID);
			TESTC(CompareVariant(&(pOldProp->vValue), &(pNewProp->vValue)));
		}
	}
	fResult = TRUE;

CLEANUP:
	return fResult;
} //TCITableDefinition::AreColEqual




//-------------------------------------------------------------------------
//
// @cmember Compare the list of old columns against the list of new columns
//------------------------------------------------------------------------- 
BOOL TCITableDefinition::AreColEqual
(
	   DBCOLUMNDESC	*oldCD, 
	   DBORDINAL	oldlen, 
	   DBCOLUMNDESC *newCD, 
	   DBORDINAL	newlen
)
{
	// when this function is called, it is supposed that m_HasAuto... were set by GetTableColumnInfo
	// and unmodified ever since
	ULONG	i;
	BOOL	fResult = FALSE;

	TESTC(oldlen == newlen);

	for (i=0; i<oldlen; i++)
	{
		TESTC(AreColEqual(&newCD[i], &oldCD[i]));
	}

	fResult = TRUE;

CLEANUP:
	return fResult;
} //TCITableDefinition::AreColEqual




//--------------------------------------------------------------------------
//
// @cmember Check the result and property status
//--------------------------------------------------------------------------
BOOL TCITableDefinition::CheckPropertyStatus(
	GUID	guidPropertySet,	// [in]	property set guid 
	GUID	guidExpectedPS,		// [in] expected prop set guid
	DBPROP	*pProp		,		// [in]	property
	HRESULT hr					// [in] the result
)
{
	BOOL		fRes = TRUE;
	BOOL		fSupported;
	BOOL		fSettable;
	VARTYPE		vtType;

	if (!pProp)
		return TRUE;
	
	// general checking
	if (DBPROPOPTIONS_REQUIRED == pProp->dwOptions && DBPROPSTATUS_OK != pProp->dwStatus)
		fRes = COMPARE(FAILED(hr), TRUE);

	if (!(guidPropertySet == guidExpectedPS) )
		// check a couple of things and returns
		return COMPARE(pProp->dwStatus, DBPROPSTATUS_NOTSUPPORTED) && COMPARE(S_OK != hr, TRUE);

	fSupported	= SupportedProperty(pProp->dwPropertyID, guidPropertySet);
	fSettable	= SettableProperty(pProp->dwPropertyID, guidPropertySet);

	if (!fSupported && !COMPARE(S_OK != hr, TRUE))
		fRes = FALSE;
		
	// status driven checking
	switch (pProp->dwStatus)
	{
		case DBPROPSTATUS_OK:
			fRes = COMPARE(fSupported != 0, TRUE);
			break;
		case DBPROPSTATUS_NOTSUPPORTED:
			fRes = COMPARE(fSupported == 0, TRUE);
			break;
		case DBPROPSTATUS_NOTSETTABLE:
			fRes = COMPARE(fSupported != 0, TRUE) && CHECK(fSettable == 0, TRUE);
			break;
		case DBPROPSTATUS_BADOPTION:
			fRes =	(pProp->dwOptions != DBPROPOPTIONS_OPTIONAL) 
				&&	COMPARE(DBPROPOPTIONS_REQUIRED != pProp->dwOptions, TRUE);
			break;
		case DBPROPSTATUS_CONFLICTING:
			fRes = COMPARE(fSettable != 0, TRUE);
			break;
		case DBPROPSTATUS_BADVALUE:
			// this could mean not supported property or value
			break;
	}

	// DBPROPSTATUS_BADVALUE can be certainly got only if type of the prop is wrong
	// info about supported discret values of the prop cannot be generacally obtained 
	// before creating an index
	vtType = GetPropInfoType(pProp->dwPropertyID, guidPropertySet);
	if (	DBPROP_COL_DEFAULT != pProp->dwPropertyID
		&&	vtType != pProp->vValue.vt
		&&	!COMPARE(DBPROPSTATUS_OK == pProp->dwStatus, FALSE))
	{
			odtLog << "ERROR: bad propstatus on improper type value on property" << pProp->dwPropertyID << "\n";
			fRes = FALSE;
	}

	return fRes;
} //TCITableDefinition::CheckProperty




//--------------------------------------------------------------------
//
// @cmember Check the prop status of a list of col desc
//	returns TRUE if all status are set consistent with prop and result
//			FALSE otherwise
//--------------------------------------------------------------------
BOOL TCITableDefinition::CheckColPropStatus(
	DBORDINAL		cColDesc,			// [in] 
	DBCOLUMNDESC	*rgColDesc,			// [in] the size of the propset array
	HRESULT			hr					// [in]	the result of the previous op
)
{
	ULONG		cPropSet;
	ULONG		cProp;
	BOOL		fRes = TRUE;
	DBORDINAL	nCol;

	if (!rgColDesc)
		return TRUE;

	for (nCol = 0; nCol < cColDesc; nCol++)
	{
		if (!rgColDesc[nCol].rgPropertySets)
			continue;
		for (cPropSet = 0; cPropSet < rgColDesc[nCol].cPropertySets; cPropSet++)
		{
			if (!rgColDesc[nCol].rgPropertySets[cPropSet].rgProperties)
				continue;
			for (cProp = 0; cProp < rgColDesc[nCol].rgPropertySets[cPropSet].cProperties; cProp++)
			{
				fRes = fRes && CheckPropertyStatus(rgColDesc[nCol].rgPropertySets[cPropSet].guidPropertySet, 
					DBPROPSET_COLUMN, &rgColDesc[nCol].rgPropertySets[cPropSet].rgProperties[cProp], hr);
			}
		}
	}
	return fRes;
} // TCITableDefinition::CheckColPropStatus




//--------------------------------------------------------------------
//
// @cmember CompareColumnDesc
//		pColumnDesc and pNewCol		[IN] parameteres to be compared
//		column addition (table creation) is assumed to have succeeded
// returns TRUE or FALSE
//--------------------------------------------------------------------
BOOL TCITableDefinition::CompareColumnDesc(
	DBCOLUMNDESC *pColumnDesc,	// [in]	column descriptor, as passed to ITableDefinition::AddColumn()
	DBCOLUMNDESC *pNewCol		// [in]	column descriptor, as read from the table after addition
)
{
	DBPROPSET	*pNewPropSet	= NULL;
	DBPROPSET	*pInPropSet		= NULL;
	DBPROP		*pInProp		= NULL;
	ULONG		j;
	ULONG		cPropSet, cProp;
	ULONG		n;
	POSITION	pos, posOld, posFind;
	CCol		col;
	BOOL		fRes = FALSE;
	GUID		gCD;

	TESTC(pColumnDesc->pTypeInfo == pNewCol->pTypeInfo);
	
	PRVTRACE("TCITableDefinition::CompareColumnDesc: pColumnDesc->wType = %d, pNewCol->wType = %d\n",  
			pColumnDesc->wType, pNewCol->wType);
	TESTC(pColumnDesc->wType == pNewCol->wType);

	TESTC(CompareDBID(pColumnDesc->dbcid, pNewCol->dbcid, m_pIDBInitialize));

	// if there is a provider type name, the column size, precision and 
	// scale of the column can be checked otherwise skip it there could 
	// be several provider types implemented on the DBTYPE
	if (!pColumnDesc->pwszTypeName)
	{
		// are multiple provider types implemented on the same DBTYPE?
		for (posFind = pos = m_ColList.GetHeadPosition(), n=0; pos;)
		{
			posOld = pos;
			col = m_ColList.GetNext(pos);
			if (col.GetProviderType() == pNewCol->wType)
			{
				n++;
				posFind = posOld;
			}
		}
		col = m_ColList.GetAt(posFind);
	}
	else
	{
		BOOL	fExistType;
		col = GetType(GetColumnTypeName(pColumnDesc), pNewCol->wType, &fExistType);
		n = fExistType ? 1: 0;
	}

	// see if there are enough data for a compColumnDescrison
	if (1 != n)
	{
		fRes = TRUE;
		goto CLEANUP;
	}

	// CHECK THE COLUMN SIZE

	// for DBTYPE_STR, DBTYPE_WSTR, DBTYPE_BSTR check whether the 
	// size of the column fits with the spec ones or the maximum
	if ((pNewCol->wType == DBTYPE_STR)  || 
		(pNewCol->wType == DBTYPE_WSTR) || 
		(pNewCol->wType == DBTYPE_BYTES)   )
	{
		LPWSTR	pwszCreateParams = col.GetCreateParams();
		if (col.GetColumnSize() >= pColumnDesc->ulColumnSize)
		{
			if (	0 != pColumnDesc->ulColumnSize 
				&&	pwszCreateParams
				&&	NULL != wcsstr(pwszCreateParams, L"length"))
				TESTC(pColumnDesc->ulColumnSize == pNewCol->ulColumnSize);
		}
		else
		{
			// Check for varchar(max), nvarchar(max), and varbinary(max) types
			if ((pColumnDesc->pwszTypeName &&
				(wcscmp(pColumnDesc->pwszTypeName, L"varchar") == 0 ||
				wcscmp(pColumnDesc->pwszTypeName, L"nvarchar") == 0 ||
				wcscmp(pColumnDesc->pwszTypeName, L"varbinary") == 0)) 

				||

				(pNewCol->wType == DBTYPE_WSTR || pNewCol->wType == DBTYPE_BYTES)
				)
			{
				//Note: we need to verify column size as read from the table after column addition (pNewCol), 
				TESTC(pNewCol->ulColumnSize	== ~(DBLENGTH)0);
			}
			else
				// column size should be set to the max column size allowed
				TESTC(col.GetColumnSize() == pNewCol->ulColumnSize);
		}
	}
	else
		if (!IsFixedLength(pNewCol->wType) && DBTYPE_VARNUMERIC != pNewCol->wType)
			TESTC(pNewCol->ulColumnSize == (DBLENGTH)~0);

	// CHECK THE PRECISION
	if (IsNumericType(pColumnDesc->wType) || DBTYPE_DBTIMESTAMP == pColumnDesc->wType)
	{
		if (0 < pColumnDesc->bPrecision)
			if (	DBTYPE_NUMERIC == pColumnDesc->wType 
				||	DBTYPE_VARNUMERIC == pColumnDesc->wType )
			{
				if (DBTYPE_VARNUMERIC != pColumnDesc->wType ) // 
					TESTC(pColumnDesc->bPrecision == pNewCol->bPrecision);
			}
			else
				TESTC(col.GetPrecision() == pNewCol->bPrecision);
	}
	else
		TESTC(pNewCol->bPrecision == (BYTE)~0);


	// CHECK SCALE
	if (	DBTYPE_NUMERIC == pColumnDesc->wType 
		||	DBTYPE_VARNUMERIC == pColumnDesc->wType 
		||	DBTYPE_DECIMAL == pColumnDesc->wType
		||	DBTYPE_DBTIMESTAMP == pColumnDesc->wType)
	{
		if (DBTYPE_VARNUMERIC != pColumnDesc->wType )
		if (	DBTYPE_DBTIMESTAMP != pColumnDesc->wType
			&&	pColumnDesc->bScale >= col.GetMinScale() 
			&&	pColumnDesc->bScale > col.GetMaxScale())
			TESTC(pColumnDesc->bScale == pNewCol->bScale);
	}
	else 
		TESTC(pNewCol->bScale == (BYTE)~0);	// as set trhough col.SetColInfo

	// get the psid
	if (pColumnDesc->pclsid)
		gCD = *pColumnDesc->pclsid;
	else
		gCD = GUID_NULL;
	
	TESTC(!m_pTable->GetHasCLSID() || gCD == *(GUID*)pNewCol->pclsid);

	if (NULL == pColumnDesc->rgPropertySets)
	{
		fRes = TRUE;
		goto CLEANUP;
	}
	for (cPropSet=0; cPropSet<(pColumnDesc->cPropertySets); cPropSet++)
	{
		pInPropSet	= &(pColumnDesc->rgPropertySets[cPropSet]);
		
		if ( pInPropSet->guidPropertySet != DBPROPSET_COLUMN )
		{
			for (cProp=0; cProp < pInPropSet->cProperties; cProp++)
				TESTC(DBPROPSTATUS_NOTSUPPORTED == pInPropSet->rgProperties[cProp].dwStatus);
			continue;
		}

		// Find matching PropSet
		for(j = 0; j < pNewCol->cPropertySets && 
			pNewCol->rgPropertySets[j].guidPropertySet != pInPropSet->guidPropertySet; j++);
		if (j >= pNewCol->cPropertySets)
			continue;

		pNewPropSet = &(pNewCol->rgPropertySets[j]);

		// compColumnDescre the propPropSet in the column prop set
		ASSERT(pNewPropSet->rgProperties);
		if (NULL == pInPropSet->rgProperties)
			continue;
		for (cProp=0; cProp < pInPropSet->cProperties; cProp++)
		{
			pInProp = &(pInPropSet->rgProperties[cProp]);

			if (pInPropSet->guidPropertySet == DBPROPSET_COLUMN)
			{

				// look for that property inside the resulted column
				if (((pInProp->dwPropertyID == DBPROP_COL_AUTOINCREMENT)	&& !m_pTable->GetHasAuto()	  )	||
					((pInProp->dwPropertyID == DBPROP_COL_DEFAULT)			&& !m_pTable->GetHasDefault() )	||
					((pInProp->dwPropertyID == DBPROP_COL_UNIQUE)			&& !m_pTable->GetHasUnique())    )
					// better check the status, it should be DBPROPSTATUS_NOTSUPPORTED
					continue;

				TESTC(		SupportedProperty(pInProp->dwPropertyID, pInPropSet->guidPropertySet) 
						||	DBPROPSTATUS_NOTSUPPORTED == pInProp->dwStatus);
				TESTC(		SettableProperty(pInProp->dwPropertyID, pInPropSet->guidPropertySet) 
						||	DBPROPSTATUS_NOTSUPPORTED == pInProp->dwStatus);

				// identify the property
				for (	j=0; 
						j< pNewPropSet->cProperties 
							&& pNewPropSet->rgProperties[j].dwPropertyID != pInProp->dwPropertyID; 
						j++);

				if (j>=pNewPropSet->cProperties)
					continue;

				// try to detect the right dbpropstatus
				TESTC(		(DBPROPSTATUS_OK != pInProp->dwStatus) 
						||	CompareVariant(&pInProp->vValue, &pNewPropSet->rgProperties[j].vValue));
			}
			// skipping the testing of other provider-specific property sets
		}
	}
	fRes = TRUE;

CLEANUP:
	return fRes;
} //TCITableDefinition::CompColumnDescreColumnDesc




//--------------------------------------------------------------------
//
// @cmember Compare the list of old columns against the list of new columns and the new column
// the place where the newly added column was added is provider specific!
//--------------------------------------------------------------------
BOOL TCITableDefinition::CheckColInfo
(
	   DBCOLUMNDESC	*oldCD, 
	   DBORDINAL	oldlen, 
	   DBCOLUMNDESC *newCD, 
	   DBORDINAL	newlen, 
	   DBCOLUMNDESC *pColumnDesc		// the new column to be add
)
{
	// when this function is called, it is supposed that m_HasAuto... were set by GetTableColumnInfo
	// and unmodified ever since
	BOOL		fNewColumn	= FALSE;
	BOOL		fResult		= FALSE;
	DBORDINAL	cOldCol;
	DBORDINAL	cNewCol;

	TESTC(newlen == oldlen+1);

	for (cOldCol=cNewCol=0; cNewCol<newlen; cNewCol++)
	{
		if (	(cOldCol < oldlen)
			&&	CompareDBID(oldCD[cOldCol].dbcid, newCD[cNewCol].dbcid, m_pIDBInitialize))
		{
			TESTC(AreColEqual(&oldCD[cOldCol], &newCD[cNewCol]));
			cOldCol++;
		}
		else
		{
			TESTC(!fNewColumn);
			TESTC(CompareColumnDesc(pColumnDesc, &newCD[cOldCol]));
			fNewColumn = TRUE;
		}
	}
	fResult = TRUE;

CLEANUP:
	return fResult;
} //TCITableDefinition::CheckColInfo




//--------------------------------------------------------------------------
//
// @cmember TCITableDefinition::CheckRowset
//--------------------------------------------------------------------------
BOOL TCITableDefinition::CheckRowset(IUnknown *pIRowset)
{
	IRowsetInfo* pInterface = NULL;
	BOOL	hr;

	if (!pIRowset)
		return TRUE;

	if (hr = DefaultObjectTesting(pIRowset, ROWSET_INTERFACE))
	{
		// just for curiosity
		if (VerifyInterface(	pIRowset, 
								IID_IRowsetInfo, 
								ROWSET_INTERFACE, 
								(IUnknown**)&pInterface)) 
		{
			IUnknown*	tempInterface;
			if (pInterface->GetSpecification(IID_IUnknown, &tempInterface) == S_FALSE)
			{ 
				// what if table ID doesn't specify a name?
				PRVTRACE(L"** No object has created the rowset");
			}
			else
			{
				IUnknown	*pIID;
				if (tempInterface->QueryInterface(IID_IGetDataSource, (void**)&pIID) == S_OK)
				{
					PRVTRACE(L"** Rowset was created by a session");
					SAFE_RELEASE(pIID);
				}
				else
					PRVTRACE(L"** Rowset was created by a command");
				SAFE_RELEASE(tempInterface);
			}
			SAFE_RELEASE(pInterface);
		}
	}
	return hr;
} //CTable::CheckRowset




//--------------------------------------------------------------------------
//
// @cmember Fills in a variant with whatever it needs
//--------------------------------------------------------------------------
BOOL TCITableDefinition::FillVariant(VARIANT *pVariant)
{
	BOOL	fRes = FALSE;
	BSTR	pwszValue = L"\'some value\'";
	WCHAR	*pwszStrValue = L"\'value\'";


	TESTC(NULL != pVariant);
	switch (pVariant->vt)
	{
		case DBTYPE_R4:
			V_R4(pVariant) = (float)3.1415926;
			break;
		case DBTYPE_R8:
			V_R8(pVariant) = 2.71828;
			break;
		case DBTYPE_BSTR:
			V_BSTR(pVariant) = SysAllocString(pwszValue);
			break;
		case DBTYPE_STR:
		case DBTYPE_WSTR:
			pVariant->vt		= DBTYPE_BSTR;
			V_BSTR(pVariant)	= SysAllocString(pwszStrValue);
			break;
		case DBTYPE_BYTES:
			V_BYREF(pVariant) = SysAllocString(pwszStrValue);
			break;
	}
	fRes = TRUE;

CLEANUP:
	return fRes;
} // TCITableDefinition::FillVariant




// @cmember Builds a default value for a given column type
BOOL TCITableDefinition::GetDefaultValue(
	DBCOLUMNDESC	*pColumnDesc,	// [in]		column descriptor	
	VARIANT			*pVariant,		// [out]	pointer to the variant that stores the default value
	CTable			*pTable			// [in]		CTable to be used (default NULL)
)
{
	TBEGIN
	CTable					*pCTable = NULL;
	CList<WCHAR *,WCHAR *>	NativeTypesList;
	CList<DBTYPE,DBTYPE>	ProviderTypesList;
	CCol					col;
	WCHAR					*pwszDefVal = NULL;
	ULONG					ulRowNum = 28;
	HRESULT					hr;

	TESTC(NULL != pColumnDesc); // && NULL != pColumnDesc->pwszTypeName);
	TESTC(NULL != pVariant);

	VariantInit(pVariant);

	if (pTable)
		pCTable = pTable;
	else
	{
		pCTable = new CTable(m_pThisTestModule->m_pIUnknown2, (LPWSTR)gwszModuleName);
		pCTable->CreateTypeColInfo(NativeTypesList, ProviderTypesList);
	}

	pCTable->GetColInfo(col, GetColumnTypeName(pColumnDesc));

	SAFE_ALLOC(pwszDefVal, WCHAR, MAXDATALEN);

	pwszDefVal[0]=L'\0';
	TESTC_(hr = col.MakeData(pwszDefVal,ulRowNum,PRIMARY,NONULLS), S_OK);

	pVariant->vt = DBTYPE_BSTR; //col.GetProviderType();
	V_BSTR(pVariant) = SysAllocString(pwszDefVal);
	SAFE_FREE(pwszDefVal);

	// Use the US_English LCID first and then the System LCID
	hr=VariantChangeTypeEx(pVariant, pVariant, MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT), VARIANT_NOVALUEPROP, col.GetProviderType());
	if(S_OK != hr)
		hr=VariantChangeTypeEx(pVariant, pVariant, GetSystemDefaultLCID(), VARIANT_NOVALUEPROP, col.GetProviderType());

	if (S_OK != hr)
	{
		// try to set it as a VT_BSTR value
		VariantClear(pVariant);
		TESTC_(pCTable->GetLiteralAndValue(col, &pwszDefVal, ulRowNum, col.GetColNum(), PRIMARY), S_OK);
		pVariant->vt = DBTYPE_BSTR;
		V_BSTR(pVariant) = SysAllocString(pwszDefVal);
		TEST2C_(hr, DISP_E_BADVARTYPE, DISP_E_TYPEMISMATCH);
	}

CLEANUP:
	SAFE_FREE(pwszDefVal);
	if (!pTable)
		delete pCTable;
	TRETURN
} // TCITableDefinition::GetDefaultValue




//--------------------------------------------------------------------------
//
// @cmember Get the number of tables in a data sources, base on IDBSchemaRowset
//--------------------------------------------------------------------------
ULONG TCITableDefinition::GetNoOfTables()
{
	IDBSchemaRowset		*pInterface = NULL;
	IRowset				*pRowset = NULL;
	DBCOUNTITEM			n=0;
	HROW *				prghRows = NULL;

	if (!VerifyInterface(m_pIOpenRowset,IID_IDBSchemaRowset, SESSION_INTERFACE, (IUnknown**)&pInterface))
	{
		PRVTRACE(L"** I could not get a pointer to IDBSchemaRowset interface");
		return 0;
	}

	TESTC_(pInterface->GetRowset(NULL, DBSCHEMA_TABLES, 0, NULL, IID_IRowset, 0, NULL, (IUnknown**)&pRowset), S_OK);

	TEST2C_(pRowset->GetNextRows(0, 0, LONG_MAX/1024, &n, &prghRows), DB_S_ENDOFROWSET, DB_S_ROWLIMITEXCEEDED );

	TESTC_(pRowset->ReleaseRows(n, prghRows, NULL, NULL, NULL), S_OK)

CLEANUP:
	SAFE_RELEASE(pRowset);
	SAFE_RELEASE(pInterface);
	PROVIDER_FREE(prghRows);
	// I dont't expect the number of tables to exceed ULONG_MAX
	ASSERT(n < ULONG_MAX);
	return (ULONG)n;	
} //TCITableDefinition::GetNoOfTables




//----------------------------------------------------------------------
//
// @cmember Drops a column and check the result against reallity
//----------------------------------------------------------------------
HRESULT	TCITableDefinition::DropColumnAndCheck(
	DBID				*pTableID,					// [in]	the table ID
	DBID				*pColumnID,					// [in]	the ID of the column to be dropped
	ITableDefinition	*pITableDefinition,/*=NULL*/	// [in] pointer to ITableDefinition interface
	DBID				*pBaseTableID/*=NULL*/		// [in] if pTableID is exotic (e.g. fuly qualified) this
													// table id is used to get metadata info about the table
)
{
	DBCOLUMNDESC	*OldColList = NULL, *NewColList = NULL;
	DBORDINAL		oldlen = 0, newlen = 0;
	ULONG			i;
	LONG			nCol = -1L;
	HRESULT			hr;
	BOOL			fTableExists	= FALSE;
	BOOL			fColumnExists	= FALSE;
	IOpenRowset		*pIOpenRowset	= NULL;
	IColumnsInfo	*pIColumnsInfo	= NULL;

	HRESULT			rgValidHRes[]	= {	S_OK,
										E_FAIL,
										E_INVALIDARG,
										DB_E_NOCOLUMN,
										DB_E_DROPRESTRICTED,
										DB_E_NOTABLE,
										DB_E_TABLEINUSE,
										DB_SEC_E_PERMISSIONDENIED,
										XACT_E_XTIONEXISTS,
							            DB_E_SCHEMAVIOLATION
									}; 

	//NOTE: spec was changed in MDAC 2.6 to replace DB_E_BADCOLUMNID with DB_E_NOCOLUMN 
	//		for ITableDefinition::DropColumn. So when runnning against MDAC 2.5 expect DB_E_BADCOLUMNID
	//      This is for SQL-specific provider. For other providers, you should modify this to test against your target spec
	HRESULT			rgValidHResMDAC25[]	= {	S_OK,
										E_FAIL,
										E_INVALIDARG,
										DB_E_BADCOLUMNID,
										DB_E_DROPRESTRICTED,
										DB_E_NOTABLE,
										DB_E_TABLEINUSE,
										DB_SEC_E_PERMISSIONDENIED,
										XACT_E_XTIONEXISTS,
							            DB_E_SCHEMAVIOLATION,
									}; 

	ULONG			cValidHRes = NUMELEM(rgValidHRes);


	if (!pBaseTableID)
		pBaseTableID = pTableID;

	if (!pITableDefinition)
		pITableDefinition = m_pITableDefinition;

	// check whether the table and column exist
	if (pTableID)
	{
		TESTC(VerifyInterface(pITableDefinition, IID_IOpenRowset, SESSION_INTERFACE, (IUnknown**)&pIOpenRowset));
		TEST2C_(hr = pIOpenRowset->OpenRowset(NULL, pTableID, NULL, IID_IColumnsInfo, 
			0, NULL, (IUnknown**)&pIColumnsInfo), S_OK, DB_E_NOTABLE);
		SAFE_RELEASE(pIOpenRowset);
		SAFE_RELEASE(pIColumnsInfo);
		fTableExists = S_OK == hr;
	}
	else
		fTableExists = FALSE;
	
	
	// this function is based on the current table name
	if (fTableExists)
	{
		GetColumnDescOnTable(pBaseTableID, &OldColList, &oldlen);
		if (pColumnID)
		{
			for (fColumnExists = FALSE, i=0; !fColumnExists && (i<oldlen); i++)
			{
				if (CompareDBID(OldColList[i].dbcid, *pColumnID, m_pIDBInitialize))
					fColumnExists = TRUE;
			}
		}
	}

	// the CHECK will be done at the caller level, where the expected return is known
	if ( (hr = m_pITableDefinition->DropColumn(pTableID, pColumnID)) != S_OK)
	{
		//NOTE: spec was changed in MDAC 2.6 to replace DB_E_BADCOLUMNID with DB_E_NOCOLUMN 
		//		for ITableDefinition::DropColumn. So when runnning against MDAC 2.5 expect DB_E_BADCOLUMNID
		//      This is for SQL-specific provider. For other providers, you should modify this to test against your target spec
		// check that the result is one of the expected results
		TESTC(CheckResult(hr, cValidHRes, g_fSQLOLEDB25 ? rgValidHResMDAC25 : rgValidHRes));

		// call failed
		if (fTableExists) //pTableID && pTableID->uName.pwszName)
		{
			GetColumnDescOnTable(pBaseTableID, &NewColList, &newlen);
			TESTC(AreColEqual(NewColList, newlen, OldColList, oldlen));
			if (!fColumnExists)
			{
				TESTC_(hr, pColumnID? (g_fSQLOLEDB25 ? DB_E_BADCOLUMNID : DB_E_NOCOLUMN): E_INVALIDARG);
			}
			else
			{
				HRESULT	rgValidHRes[] = {DB_E_DROPRESTRICTED, DB_E_TABLEINUSE, DB_SEC_E_PERMISSIONDENIED, XACT_E_XTIONEXISTS, E_FAIL};

				// check the possible results
				TESTC(CheckResult(hr, NUMELEM(rgValidHRes), rgValidHRes));
			}
		}
		else 
		{
			if (pTableID)
			{	
				TEST2C_(hr, DB_E_NOTABLE, (g_fSQLOLEDB25 ? DB_E_BADCOLUMNID : DB_E_NOCOLUMN)); 
			}
			else
				TESTC_(hr, E_INVALIDARG);
		}
	}
	else
	{
		// call succeeded
		TESTC(fColumnExists);
		GetColumnDescOnTable(pBaseTableID, &NewColList, &newlen);
		for (i = 0, nCol = -1; i < oldlen && nCol < 0; i++)
		{
			if (CompareDBID(OldColList[i].dbcid, *pColumnID, m_pIDBInitialize))
				nCol = (ULONG)i;
		}

		TESTC(0 <= nCol);

		// this should work even when the column name is not in the original (old) table
		TESTC(CheckColInfo(NewColList, newlen, OldColList, oldlen, &OldColList[nCol]));
	}

CLEANUP:
	SAFE_RELEASE(pIOpenRowset);
	SAFE_RELEASE(pIColumnsInfo);
	ReleaseColumnDesc(OldColList, oldlen);
	ReleaseColumnDesc(NewColList, newlen);
	return hr;
} // TCITableDefinition::DropColumnAndCheck




//--------------------------------------------------------------------------
//
// @cmember Drops a table and check the operation
//--------------------------------------------------------------------------
HRESULT TCITableDefinition::DropTableAndCheck(
	DBID				*pTableID,							// [in] ID of the table to be dropped
	ITableDefinition	*pITableDefinition /*=NULL*/		// [in] pointer to ITableDefinition interface
)
{
	BOOL	fExists;
	BOOL	fTableExisted;
	CTable	*pTable = new CTable(m_pThisTestModule->m_pIUnknown2, (LPWSTR)gwszModuleName);
	HRESULT	hRes;

	ASSERT(pTable);
	if (!pITableDefinition)
		pITableDefinition = m_pITableDefinition;

	// check whether the table existed before
	CHECK(pTable->DoesTableExist(pTableID, &fTableExisted), S_OK);

	// drop the table 
	hRes = pITableDefinition->DropTable(pTableID);

	// check that if table was dropped it doesn't exist
	TESTC(fTableExisted || !SUCCEEDED(hRes));
	TESTC_(pTable->DoesTableExist(pTableID, &fExists), S_OK);
	TESTC(!fTableExisted || fExists == !SUCCEEDED(hRes));

CLEANUP:
	delete pTable;
	return hRes;
} //TCITableDefinition::DropTableAndCheck




//--------------------------------------------------------------------------
//
// GetInfo about table identifiers
//--------------------------------------------------------------------------
HRESULT	TCITableDefinition::GetLiteralInfo()
{
	IDBInfo*		pInterface = NULL;
	DBLITERAL		rgLiteral[2]={DBLITERAL_TABLE_NAME, DBLITERAL_COLUMN_NAME};
	DBLITERALINFO*	rgLiteralInfo = NULL;
	ULONG			cLiteralInfo, i;
	OLECHAR*		pCharBuffer = NULL;
	IGetDataSource*	pIGetDataSource=NULL;	// IGetDataSource interface pointer

	m_fIsIDBInfo = FALSE;

	if(!VerifyInterface(m_pIOpenRowset, IID_IGetDataSource, SESSION_INTERFACE, (IUnknown**)&pIGetDataSource))
		return E_FAIL;

	m_hr=pIGetDataSource->GetDataSource(IID_IDBInfo,(IUnknown**)&pInterface);
	SAFE_RELEASE(pIGetDataSource);

	if (!CHECK(pInterface->GetLiteralInfo(2, rgLiteral, &cLiteralInfo, &rgLiteralInfo, &pCharBuffer), S_OK))
		goto CLEANUP;

	for (i=0; i< cLiteralInfo; i++)
	{
		switch (rgLiteralInfo[i].lt)
		{
		case DBLITERAL_TABLE_NAME:
			// get the maximum size of a valid table name and the invalid chars for a table name
			m_cMaxTableName = rgLiteralInfo[i].cchMaxLen;
			PROVIDER_FREE(m_pwszInvalidTableChars);
			m_pwszInvalidTableChars = wcsDuplicate(rgLiteralInfo[i].pwszInvalidChars?
				rgLiteralInfo[i].pwszInvalidChars: L"");
			break;
		case DBLITERAL_COLUMN_NAME:
			m_cMaxColName = rgLiteralInfo[i].cchMaxLen;
			PROVIDER_FREE(m_pwszInvalidColChars);
			m_pwszInvalidColChars = wcsDuplicate(rgLiteralInfo[i].pwszInvalidChars?
				rgLiteralInfo[i].pwszInvalidChars: L"");
			break;
		}
	}

	m_fIsIDBInfo = TRUE;

CLEANUP:
	SAFE_RELEASE(pInterface);
	PROVIDER_FREE(pCharBuffer);
	PROVIDER_FREE(rgLiteralInfo);
	return m_hr;
} //TCITableDefinition::GetLiteralInfo





// @cmember Gets the catalog and schema name for a given table
BOOL	TCITableDefinition::GetCatalogSchemaNames(
	LPWSTR	pwszTableName,		// [in]		the name of the table
	LPWSTR	*ppwszCatalogName,	// [out]	catalog name
	LPWSTR	*ppwszSchemaName,	// [out]	schema name
	CTable	*pTable				// [in]		table object (DEFAULT NULL - use m_pTable)
)
{
    IRowset		*pIRowset = NULL;
	HROW		hRow = DB_NULL_HROW;
	BOOL		bFound = FALSE;
	WCHAR		*pwszTableName1 = NULL;
	CRowset		Rowset;

	if (!pTable)
		pTable = m_pTable;
	TESTC(NULL != pwszTableName);
	TESTC(NULL != ppwszCatalogName);
	TESTC(NULL != ppwszSchemaName);

	//Obtain Schema TABLES Rowset
	//We don't want to put any restrictions, since its not required to support 
	//restrictions...
	TESTC_PROVIDER((Rowset.CreateRowset(SELECT_DBSCHEMA_TABLE, 
		IID_IRowset, pTable, DBACCESSOR_ROWDATA, DBPART_ALL, ALL_COLS_BOUND)==S_OK));
	
	//Try to find the specified row with this table...
	while(!bFound && S_OK == (m_hr = Rowset.GetNextRows(&hRow)))
	{
		//GetData for this row
		TESTC_(Rowset.GetRowData(hRow, &Rowset.m_pData),S_OK);

		//TABLE_NAME column
		DBBINDING* pCatalogBinding	= Rowset.m_rgBinding[0].iOrdinal == 0 ? &Rowset.m_rgBinding[1] : &Rowset.m_rgBinding[0];
		DBBINDING* pSchemaBinding	= Rowset.m_rgBinding[0].iOrdinal == 0 ? &Rowset.m_rgBinding[2] : &Rowset.m_rgBinding[1];
		DBBINDING* pTableBinding	= Rowset.m_rgBinding[0].iOrdinal == 0 ? &Rowset.m_rgBinding[3] : &Rowset.m_rgBinding[2];

		//See if this is the correct row...
		if(STATUS_BINDING(*pTableBinding, Rowset.m_pData)==DBSTATUS_S_OK)
		{
			//TableName
			pwszTableName1 = (WCHAR*)&VALUE_BINDING(*pTableBinding, Rowset.m_pData);
			bFound = FALSE;
			if(CHECK(CompareID(&bFound, pwszTableName, 
					pwszTableName1, m_pIDBInitialize), S_OK) && bFound)
			{	
				//Catalog Name
				if(STATUS_BINDING(*pCatalogBinding, Rowset.m_pData)==DBSTATUS_S_OK)
					*ppwszCatalogName = wcsDuplicate((WCHAR*)&VALUE_BINDING(*pCatalogBinding, Rowset.m_pData));
				//Schema Name
				if(STATUS_BINDING(*pSchemaBinding, Rowset.m_pData)==DBSTATUS_S_OK)
					*ppwszSchemaName = wcsDuplicate((WCHAR*)&VALUE_BINDING(*pSchemaBinding, Rowset.m_pData));
			}
		}

		Rowset.ReleaseRows(hRow);
		hRow = DB_NULL_HROW;
	}

	//Error
	if(!bFound)
	{
		TERROR("Unable to find the table \"" << pwszTableName << "\"in the Schema Rowset?");
		QTESTC(bFound);
		return FALSE;
	}
CLEANUP:
	if (DB_NULL_HROW != hRow)
		Rowset.ReleaseRows(hRow);
	SAFE_RELEASE(pIRowset);
	return TRUE;
} //TCITableDefinition::GetCatalogSchemaNames




//--------------------------------------------------------------------------
//
// @cmember Build a valid table name of a certain length
//--------------------------------------------------------------------------
WCHAR* TCITableDefinition::BuildValidName(size_t length, WCHAR* pattern)
{
	WCHAR*	pwszBuffer = NULL;
	size_t	cLen = wcslen(pattern), i;

	SAFE_ALLOC(pwszBuffer, WCHAR, i=(length+1));
	memset(pwszBuffer, 0, i);
	for (i=0; i< length - cLen; i+=cLen)
		wcscat(pwszBuffer, pattern);
	// manage the rest of the characters
	wcsncat(pwszBuffer, pattern, length-i);
CLEANUP:
	return pwszBuffer;
} //TCITableDefinition::BuildValidName




//--------------------------------------------------------------------------
//
// @cmember Build an invalid table name of a certain length
// the pattern is supposed to be shorter than the string to be build
//--------------------------------------------------------------------------
WCHAR* TCITableDefinition::BuildInvalidName(size_t length, WCHAR* pattern, WCHAR* invchars)
{
	WCHAR*	pwszBuffer=NULL;
	size_t	cLen = wcslen(pattern), i, cInvLen=wcslen(invchars);

	pwszBuffer = (WCHAR*) PROVIDER_ALLOC( (length + 1) * sizeof(WCHAR) );
	if (!pwszBuffer)
		goto CLEANUP;

	if (length > cInvLen+cLen)
	{
		wcscpy(pwszBuffer, pattern);
		wcscat(pwszBuffer, invchars);
	}
	else
	{
		wcscpy(pwszBuffer, L"aa");
		wcsncat(pwszBuffer, invchars, length-wcslen(pwszBuffer)-1);
		pwszBuffer[length] = 0;
		assert( wcslen(pwszBuffer) < length );
		return pwszBuffer;
	}
	for (i=wcslen(pwszBuffer); i< length - cLen; i+=cLen)
		wcscat(pwszBuffer, pattern);
	// manage the rest of the characters
	for (; i<length; i++)
		wcscat(pwszBuffer, L"a");

CLEANUP:
	return pwszBuffer;
} //TCITableDefinition::BuildInvalidName




//---------------------------------------------------------------------
//
// @cmember Uses m_pTable to get a column description for all types
//---------------------------------------------------------------------
void TCITableDefinition::GetProviderTypes(void)
{
	CList <WCHAR*, WCHAR*>	ListNativeTemp;
	CList <DBTYPE, DBTYPE>	ListDataTypes;

	if (m_pTable)
		delete m_pTable;

	m_pTable = new CTable(m_pThisTestModule->m_pIUnknown2, (LPWSTR)gwszModuleName);
	// get the provider types list
	// all types appear in CreateColList, so I don't have to use CreateTypeColInfo
	m_pTable->CreateTypeColInfo(ListNativeTemp, ListDataTypes, ALLTYPES);
	m_pTable->DuplicateColList(m_ColList);
	// in m_rgColumnDesc I would rather load just the types prepared for table creation
	m_pTable->CreateColInfo(ListNativeTemp, ListDataTypes, ALLTYPES);
	// build the column description array
	m_pTable->BuildColumnDescs(&m_rgColumnDesc);
	m_cColumnDesc = m_pTable->CountColumnsOnTable();
	m_pTable->SetBuildColumnDesc(FALSE);
	ReleaseAllColumnPropSets(m_rgColumnDesc, m_cColumnDesc);
	delete m_pTable;
	m_pTable = NULL;
} //TCITableDefinition::GetProviderTypes




//---------------------------------------------------------------------
//
// @cmember Sets all the columns to maximum size as got from m_ColList 
// (based on information read from PROVIDER_TYPES Rowset)
//
// RESULT:
//		TRUE	- set for every element in column desc array
//		FALSE	- could not be set for every element in thee array
//---------------------------------------------------------------------
BOOL TCITableDefinition::SetMaximumColSize
(
	DBCOLUMNDESC	*rgColumnDesc, 
	DBORDINAL		cColumnDesc
)
{
	POSITION	pos;
	CCol		col;
	DBORDINAL	i;
	WCHAR		*pwszType;

	for (i=0; i<cColumnDesc; i++)
	{
		pwszType = GetColumnTypeName(&rgColumnDesc[i]);

		// look for the type which fits with column type
		for (	pos=m_ColList.GetHeadPosition(), col=m_ColList.GetNext(pos);
				wcscmp(col.GetProviderTypeName(), pwszType) && pos; 
				col=m_ColList.GetNext(pos));
		if (wcscmp(col.GetProviderTypeName(), pwszType) )
			continue;
		// set to max column size
		rgColumnDesc[i].ulColumnSize = col.GetColumnSize();
	}
	return TRUE;
} //TCITableDefinition::SetMaximumColSize




//--------------------------------------------------------------------------
//
// @cmember Sets all the column sizes to 0
// RESULT:
//	TRUE	- set for every element in column desc array
//	FALSE	- could not be set for every element in thee array
//--------------------------------------------------------------------------
BOOL TCITableDefinition::SetZeroColSize
(
	DBCOLUMNDESC	*rgColumnDesc, 
	DBORDINAL		cColumnDesc
)
{
	DBORDINAL	i;

	for (i=0; i<cColumnDesc; i++)
	{
		// set column size to 0
		rgColumnDesc[i].ulColumnSize = 0;
	}
	return TRUE;
} //TCITableDefinition::SetZeroColSize




//--------------------------------------------------------------------------
//
// @cmember CheckReturnedDBID about the columns in the table
//	pIndexID		-	[IN] the DBID asked for
//	ppIndexID		-	[IN] the DBID created
//--------------------------------------------------------------------------
BOOL TCITableDefinition::CheckReturnedDBID(
	DBID	*pIndexID,		// passed to CreateIndex
	DBID	**ppIndexID		// returned by CreateIndex
)
{
	if (!pIndexID)
		return *ppIndexID != NULL;

	if (!ppIndexID)
	{
		return TRUE;
	}

	if (*ppIndexID == NULL)
		return FALSE;

	if (pIndexID->eKind != (*ppIndexID)->eKind)	
		return TRUE;

	return CompareDBID(*pIndexID, **ppIndexID);
} //TCITableDefinition::CheckReturnedDBID




//--------------------------------------------------------------------------
//
// @cmember GetInfo about the columns in the table
//	prgInfo			-	[OUT] the array of column information
//	pcColumns		-	[OUT] the size of the array
//	ppStringBuffer	-	[OUT] memory for info in the array
//--------------------------------------------------------------------------
BOOL TCITableDefinition::GetColumnInfo
(
	DBID			*pTableID, 
	DBORDINAL		*pcColumns, 
	DBCOLUMNINFO	**prgInfo, 
	OLECHAR			**ppStringBuffer
)
{
	IColumnsInfo	*pIColumnsInfo;

	if ( (m_hr = m_pIOpenRowset->OpenRowset(NULL, pTableID, NULL, IID_IColumnsInfo, 
				0, NULL, (IUnknown**)&pIColumnsInfo)) != S_OK)
	{
		*prgInfo			= NULL;
		*pcColumns			= 0;
		*ppStringBuffer	= NULL;
		return FALSE;
	}

	if (!CHECK(m_hr = pIColumnsInfo->GetColumnInfo(pcColumns, prgInfo, ppStringBuffer), S_OK))
		return FALSE;

	SAFE_RELEASE(pIColumnsInfo);
	return TRUE;
} //TCITableDefinition::GetColumnInfo




//---------------------------------------------------------------------
//
// @cmember Get an array od Column Descriptors on a Table
//---------------------------------------------------------------------
BOOL TCITableDefinition::GetColumnDescOnTable(
	DBID			*pTableID, 
	DBCOLUMNDESC	**prgColumnDesc, 
	DBORDINAL		*cColumnDesc
)
{
	if (!m_pTable)
		return FALSE;

	// get info in m_pTable->m_ColList
	m_pTable->GetTableColumnInfo(pTableID);
	m_pTable->AddInfoFromColumnsSchemaRowset(m_pITableDefinition, 
		pTableID || DBKIND_NAME != pTableID->eKind? pTableID->uName.pwszName: NULL);
	m_pTable->ColList2ColumnDesc(prgColumnDesc, cColumnDesc);
	return TRUE;
} //TCITableDefinition::GetColumnDescOnTable




//---------------------------------------------------------------------
//
// @cmember Passes a type name and retrieves the column from m_ColList with info about that type
//---------------------------------------------------------------------
CCol TCITableDefinition::GetType(WCHAR *pwszTypeName, DBTYPE wType, BOOL *fExists)
{
	POSITION	pos;
	CCol		col;
	BOOL		fRes = FALSE;

	for (pos = m_ColList.GetHeadPosition(); pos && !fRes; )
	{
		col		= m_ColList.GetNext(pos);
		fRes	=	(0 == wcscmp(col.GetProviderTypeName(), pwszTypeName))
				&&	(wType == col.GetProviderType());
	}

	if (fExists)
		*fExists = fRes;

	return fRes? col : m_ColList.GetHead();
} //TCITableDefinition::GetType




//------------------------------------------------------------------------
//
// @mfunc Check whether the array of ColumnDesc sent was preserved
// @rdesc TRUE or FALSE
// All the data should be inside, the only thing that is allowed to be modified <nl>
// is the property status
//------------------------------------------------------------------------
BOOL TCITableDefinition::IsColumnDescPreserved
(
	DBCOLUMNDESC	*rgInColumnDesc,	// the array passed to ITableDefinition::CreateTable
	DBCOLUMNDESC	*rgOutColumnDesc,	// the aray returned by ITableDefinition::CreateTable
	DBORDINAL		cColumnDesc			// the size of the arrays
)
{
		// when this function is called, it is supposed that m_HasAuto... were set by GetTableColumnInfo
	// and unmodified ever since
	ULONG		i, cPropSets, cProp;
	DBPROPSET	*pInPropSet, *pOutPropSet;

	if (NULL == rgInColumnDesc || NULL == rgOutColumnDesc)
		return (0 == cColumnDesc) || (rgOutColumnDesc == rgInColumnDesc);

	for (i=0; i<cColumnDesc; i++)
	{
		// compare everything in the stru
		if (!CHECK(rgInColumnDesc[i].pTypeInfo == rgOutColumnDesc[i].pTypeInfo, TRUE))
			return FALSE;
		if (!CHECK(rgInColumnDesc[i].ulColumnSize == rgOutColumnDesc[i].ulColumnSize, TRUE))
			return FALSE;
		if (!CHECK(rgInColumnDesc[i].wType == rgOutColumnDesc[i].wType, TRUE))
			return FALSE;
		if (!CHECK(rgInColumnDesc[i].bPrecision == rgOutColumnDesc[i].bPrecision, TRUE))
			return FALSE;
		if (!CHECK(rgInColumnDesc[i].bScale == rgOutColumnDesc[i].bScale, TRUE))
			return FALSE;
		if (!CHECK(rgInColumnDesc[i].pclsid == rgOutColumnDesc[i].pclsid, TRUE))
			return FALSE;
		if (INVALID_DBKIND != rgInColumnDesc[i].dbcid.eKind)
		{
			// CompareDBID with NULL DSO interface since the ids should
			// match exactly
			if (!CHECK(m_hr = CompareDBID(rgInColumnDesc[i].dbcid, 
				rgOutColumnDesc[i].dbcid, NULL), TRUE))
				return FALSE;
		}
		else
			if (INVALID_DBKIND != rgOutColumnDesc[i].dbcid.eKind)
				return FALSE;
		// compare the properties
		if (!CHECK(rgInColumnDesc[i].cPropertySets == rgOutColumnDesc[i].cPropertySets, TRUE))
			return FALSE;
		if (	(NULL == rgInColumnDesc[i].rgPropertySets)
			||	(NULL == rgOutColumnDesc[i].rgPropertySets))
			if (	0 != rgOutColumnDesc[i].cPropertySets 
				&&	!COMPARE(rgInColumnDesc[i].rgPropertySets, rgOutColumnDesc[i].rgPropertySets))
				return FALSE;
			else
				continue;
		for (cPropSets=0; cPropSets<rgInColumnDesc[i].cPropertySets; cPropSets++)
		{
			// compare the props in that prop set
			pInPropSet	= &(rgInColumnDesc[i].rgPropertySets[cPropSets]);
			pOutPropSet	= &(rgOutColumnDesc[i].rgPropertySets[cPropSets]);

			if (!CHECK(pInPropSet->guidPropertySet == pOutPropSet->guidPropertySet, TRUE))
				return FALSE;
			if (!CHECK(pInPropSet->cProperties == pOutPropSet->cProperties, TRUE))
				return FALSE;
			if (	(NULL == pInPropSet->rgProperties)
				||	(NULL == pOutPropSet->rgProperties))
				if (0 != pOutPropSet->cProperties 
					&& !COMPARE(pInPropSet->rgProperties, pOutPropSet->rgProperties))
					return FALSE;
				else
					continue;
			
			// compare the properties
			for (cProp=0; cProp<pInPropSet->cProperties; cProp++)
			{
				if (!CHECK(pInPropSet->rgProperties[cProp].dwPropertyID == 
						   pOutPropSet->rgProperties[cProp].dwPropertyID, TRUE))
					return FALSE;
				if (!CHECK(pInPropSet->rgProperties[cProp].dwOptions == 
						   pOutPropSet->rgProperties[cProp].dwOptions, TRUE))
					return FALSE;
				// use NULL fr DSO interface
				if (!CHECK(m_hr = CompareDBID(pInPropSet->rgProperties[cProp].colid, 
						   pOutPropSet->rgProperties[cProp].colid, 
						   NULL), TRUE))
					return FALSE;
				// protection against assertion errors in CompareVariant
				if (
					 (rgInColumnDesc[i].wType != DBTYPE_GUID)	&&
					 (rgInColumnDesc[i].wType != DBTYPE_BYTES)	&&
					 (rgInColumnDesc[i].wType != DBTYPE_STR)	&&
					 (rgInColumnDesc[i].wType != DBTYPE_WSTR)	&&
					 (rgInColumnDesc[i].wType != DBTYPE_NUMERIC)	&&
					 (rgInColumnDesc[i].wType != DBTYPE_DBTIMESTAMP)
					)
					if (!CHECK(CompareVariant(&pInPropSet->rgProperties[cProp].vValue,
							   &pOutPropSet->rgProperties[cProp].vValue), TRUE))
						return FALSE;
			}
		}
	}
	return TRUE;
} //TCITableDefinition::IsColumnDescPreserved
				



//---------------------------------------------------------------------
//
// @cmember Set a property in the property sets of a DBCOLUMNDESC
//---------------------------------------------------------------------
BOOL TCITableDefinition::SetProperty
(
	DBPROPSET		**prgPropertySets,					// [in/out]		array of property sets
	ULONG			*pcPropertySets,					// [in/out]		number of property sets
	DBPROPID		propID,								// [in]			property ID
	DBTYPE			wType,								// [in]			value type
	LPVOID			value,								// [in]			property value
	DBPROPOPTIONS	dwOption/*=DPROPOPTIONS_OPTIONAL*/,	// [in]			prop options
	DBID			colid/*=DB_NULLID*/,				// [in]			col id
	GUID			guidPropertySet/*DBPROPSET_COLUMN*/,// [in]			the GUID of the propset
	ULONG			*pcPropSet/*=NULL*/,				// [out]		index of property set 
	ULONG			*pcProp/*=NULL*/					// [out]		index in the rgProperties array
)
{
	LONG		i;
	DBPROPSET	*pPropSet;
	BOOL		fRes = FALSE, fFound;
	ULONG		cPropSet, cProp;

	if (wType != DBTYPE_VARIANT)
	{
		TESTC(::SetProperty(propID, guidPropertySet, pcPropertySets, prgPropertySets, value,
			wType, dwOption, colid));
	}
	else
	{
		TESTC(::SetProperty(propID, guidPropertySet, pcPropertySets, prgPropertySets, value,
			VT_I2, dwOption, colid));
	}

	
	fRes = TRUE;

	for (i=(int)(*pcPropertySets - 1), fFound = FALSE; i >= 0 && !fFound; i--)
	{
		fFound = (*prgPropertySets)[i].guidPropertySet == guidPropertySet;
		cPropSet = (ULONG)i;
	}

	TESTC(fFound);

	pPropSet = &((*prgPropertySets)[cPropSet]);
	for (i=pPropSet->cProperties - 1, fFound = FALSE; i >= 0 && !fFound; i--)
	{
		if (TRUE == (fFound = pPropSet->rgProperties[i].dwPropertyID == propID))
		{
			cProp = (ULONG)i;
			if (DBTYPE_VARIANT == wType)
			{
				pPropSet->rgProperties[i].vValue.vt = ((VARIANT*)value)->vt;
				FillVariant(&pPropSet->rgProperties[i].vValue);
			}
		}
	}

	if (pcPropSet)
		*pcPropSet = cPropSet;

	if (pcProp)
		*pcProp = cProp;

	TESTC(fFound);
	fRes = TRUE;

CLEANUP:
	return fRes;
} //TCITableDefinition::SetProperty




//---------------------------------------------------------------------------
//
// @cmember Set a default property in the property sets of a DBCOLUMNDESC
//---------------------------------------------------------------------------
BOOL TCITableDefinition::SetDefaultProperty(
	DBPROPSET		**prgPropertySets,						// [in/out]		array of property sets
	ULONG			*pcPropertySets,						// [in/out]		number of property sets
	VARIANT			*pvalue,								// [in]			property value
	DBPROPOPTIONS	dwOption /*= DBPROPOPTIONS_OPTIONAL*/,	// [in]			prop options
	DBID			colid /*= DB_NULLID*/,					// [in]			col id
	GUID			guidPropertySet /*= DBPROPSET_COLUMN*/,	// [in]			the GUID of the propset
	ULONG			*pcPropSet /*= NULL*/,					// [out]		index of property set 
	ULONG			*pcProp /*=NULL*/						// [out]		index in the rgProperties array
)
{
	BOOL	fRes = FALSE;
	ULONG	cPropSet;
	ULONG	cProp;

	TESTC(NULL != pvalue);
	TESTC(SetProperty(prgPropertySets, pcPropertySets, DBPROP_COL_DEFAULT, 
		DBTYPE_I2, 0, dwOption, colid, DBPROPSET_COLUMN, &cPropSet, &cProp));

	VariantCopy(&((*prgPropertySets)[cPropSet].rgProperties[cProp].vValue), pvalue);
	if (pcPropSet)
		*pcPropSet = cPropSet;
	if (pcProp)
		*pcProp = cProp;
	fRes = TRUE;

CLEANUP:
	return fRes;
} // TCITableDefinition::SetDefaultProperty




//---------------------------------------------------------------------------
// TCITableDefinition::Insert
//
// CTable				|
// Insert				|
// Inserts 1 row in table using IRowsetNewRow. This function is called
// by the pulic Insert function.
//
// @mfunc	Insert
// @rdesc HRESULT indicating success or failure
// 	@flag S_OK		| Function ran without problem
// 	@flag E_FAIL	| No Columns Marked for use or SetNewData failed
//
//---------------------------------------------------------------------------
HRESULT TCITableDefinition::Insert(			
	DBCOUNTITEM		ulRowNumber,		// @parm [IN]	Row number to insert	(0 for next)		
	IUnknown		*pIUnknown,			// @parm [IN]	Pointer to rowset interface
	ULONG			cNulls,				// @parm [IN]	Number of columns to be set to NULL (DEFAULT 0)
	DBORDINAL		*rgNulls,			// @parm [IN]	Array of columns to be set to NULL (DEFAULT NULL)
	CTable			*pTable				// @parm [IN]	Table (DEFAULT NULL - use m_pTable)
)
{
	HRESULT				hr				= E_FAIL;
	HACCESSOR			hAccessor		= NULL;
	BYTE*				pData			= NULL;
	DBCOUNTITEM			cBindings		= 0;
	DBBINDING*			rgBindings		= NULL;
	IDBProperties*		pIDBProperties	= NULL;
	IGetDataSource*		pIGetDataSource	= NULL;
	ULONG				nBinding, nNull;
	BOOL				fFound;
	IRowsetChange		*pIRowsetChange	= NULL;
	IAccessor			*pIAccessor		= NULL;
	ULONG				cRefCounts		= ULONG_MAX;

	if (!pTable)
		pTable = m_pTable;

	// Find row number to use on insert
	if (ulRowNumber == 0)
		ulRowNumber = pTable->GetNextRowNumber();

	TESTC(NULL != pIUnknown);
	TESTC(VerifyInterface(pIUnknown, IID_IAccessor, ROWSET_INTERFACE, (IUnknown**)&pIAccessor));
	TESTC(VerifyInterface(pIUnknown, IID_IRowsetChange, ROWSET_INTERFACE, (IUnknown**)&pIRowsetChange));

	//Get the DataSource
	TESTC(VerifyInterface(m_pIOpenRowset, IID_IGetDataSource, SESSION_INTERFACE, (IUnknown**)&pIGetDataSource));
	TESTC_(hr = pIGetDataSource->GetDataSource(IID_IDBProperties, (IUnknown**)&pIDBProperties), S_OK);

	//Get an accessor with all the writeable columns
	TESTC_(hr = GetAccessorAndBindings(pIRowsetChange, 
		DBACCESSOR_ROWDATA,
		&hAccessor, &rgBindings, &cBindings, NULL,
		DBPART_VALUE |DBPART_STATUS |DBPART_LENGTH,
		UPDATEABLE_COLS_BOUND, FORWARD, NO_COLS_BY_REF, NULL,
		NULL, NULL,	DBTYPE_EMPTY, 0, NULL), S_OK);

	// Fill buffer with appropriate data for insert of this row number
	TESTC_(hr = FillInputBindings(
		pTable,
		DBACCESSOR_ROWDATA,		
		cBindings,
		rgBindings,	
		&pData,		
		ulRowNumber,						
		0,
		NULL),S_OK);

	// set the NULL columns
	for (nBinding = 0; nBinding < cBindings; nBinding++)
	{
		for (fFound = FALSE, nNull = 0; nNull < cNulls && !fFound; nNull++)
		{
			if (rgBindings[nBinding].iOrdinal == rgNulls[nNull])
			{
				*(DBSTATUS*)(pData+rgBindings[nBinding].obStatus) = DBSTATUS_S_ISNULL;
				fFound = TRUE;
			}
		}
	}

	// release previous accessor and create a new one
	hr = pIRowsetChange->InsertRow(NULL, hAccessor, pData, NULL);

	if (DB_E_ERRORSOCCURRED == hr)
	{	
		SHORT	*pMyData;

		for (ULONG i=0; i<cBindings; i++)
		{
			pMyData = (SHORT*)(pData+rgBindings[i].obStatus);
			if (DBSTATUS_S_OK != *pMyData && DBSTATUS_E_UNAVAILABLE != *pMyData)
				odtLog << "bindings " << i << "\n";
		}

	}
	// We have successfully inserted if we got this far
	pTable->AddRow(); //increments pTable->m_ulNextRow

CLEANUP:
	if(hAccessor && pIAccessor)
	{
		pIAccessor->ReleaseAccessor(hAccessor, &cRefCounts);
		COMPARE(cRefCounts,0);
	}

	SAFE_RELEASE(pIAccessor);
	FreeAccessorBindings(cBindings, rgBindings);
	PROVIDER_FREE(pData);

	SAFE_RELEASE(pIRowsetChange);
	SAFE_RELEASE(pIGetDataSource);
	SAFE_RELEASE(pIDBProperties);
	return hr;
} //TCITableDefinition::Insert




//--------------------------------------------------------------------------
//
// @cmember StartTransaction method
//	RETURN
//		S_OK	- an isolation level could be set and a transaction started
//		E_FAIL	- could not start a transaction
//--------------------------------------------------------------------------
HRESULT TCITableDefinition::StartTransaction(ITransactionLocal *pITransactionLocal)
{
	ULONG		n, i;
	HRESULT		hr;
	ISOLEVEL	rgIsoLevel[] = {ISOLATIONLEVEL_BROWSE, ISOLATIONLEVEL_CURSORSTABILITY,
								ISOLATIONLEVEL_ISOLATED, ISOLATIONLEVEL_CHAOS};

	if (NULL == pITransactionLocal)
		return E_FAIL;
	
	n = NUMELEM(rgIsoLevel);
	for (i=0; i<n; i++)
	{
		if (S_OK == (hr = pITransactionLocal->StartTransaction(rgIsoLevel[i], 0, NULL, NULL)))
		{
			return S_OK;
		}
	}
	return E_FAIL;
} //TCITableDefinition::StartTransaction




//---------------------------------------------------------------------
//
//	TCITableDefinition::AddColumnAndCheck
//
// Add a column to the table and check the result
// RETURN value is the ret value of ITableDefinition::AddColumn
//---------------------------------------------------------------------
HRESULT TCITableDefinition::AddColumnAndCheck(
		DBID				*pTableID,					// [IN]  table ID
		DBCOLUMNDESC		*pColumnDesc,				// [IN]  descriptor of the column to be added
		DBID				**ppColumnID,				// [OUT] column ID for the resulted column
		ITableDefinition	*pITableDefinition,/*= NULL*/// [IN]  pointer to ITableDefinition 
		DBID				*pBaseTableID/*= NULL*/	// [IN] if provided, this is the table DBID that should be used
														// in metadata comparison (e.g. pTableID might be the qualified name)
)
// sometimes there is not a unique expected result (e.g. one property could be supported or not)
// using Validate == FALSE you can protect the code from getting errors
{
	DBCOLUMNDESC	*rgOldCD				= NULL;
	DBORDINAL		nOldlen					= 0;
	DBCOLUMNDESC	*rgNewCD				= NULL;
	DBORDINAL		nNewlen					= 0;
	DBCOLUMNDESC	*pOriginalColumnDesc	= NULL;
	BOOL			fRes					= TRUE;
	HRESULT			hr						= E_FAIL;

	if (!pBaseTableID)
		pBaseTableID = pTableID;

	pITableDefinition = (NULL == pITableDefinition) ? m_pITableDefinition: pITableDefinition;
	TESTC(NULL != pITableDefinition);

	GetColumnDescOnTable(pBaseTableID, &rgOldCD, &nOldlen);
	if (ppColumnID)
		*ppColumnID = NULL;

	CHECK(NULL == pColumnDesc
		|| NULL != DuplicateColumnDesc(pColumnDesc, 1, &pOriginalColumnDesc), TRUE);

	// here use pTableID, everywhere else use pBaseTableID
	hr = pITableDefinition->AddColumn(pTableID, pColumnDesc, ppColumnID);

	if (	pOriginalColumnDesc
		&&	!COMPARE(IsColumnDescPreserved(pOriginalColumnDesc, pColumnDesc, 1), TRUE))
	{
		odtLog << "\tERROR: column desc is not preserved\n";
	}

	// check the status of the column properties
	COMPARE(CheckColPropStatus(1, pColumnDesc, hr), TRUE);

	if (FAILED(hr) && ppColumnID)
		COMPARE(NULL == *ppColumnID, TRUE);
	
	// get the new stru of the table
	GetColumnDescOnTable(pBaseTableID, &rgNewCD, &nNewlen);

	// check the result of the operation
	if (SUCCEEDED(hr))
		// get info about the columns in the altered table and compare them, one by one!
		COMPARE(CheckColInfo(rgOldCD, nOldlen, rgNewCD, nNewlen, pColumnDesc), TRUE);
	else
		// make sure that the table stru remained the same
		COMPARE(AreColEqual(rgOldCD, nOldlen, rgNewCD, nNewlen), TRUE);

CLEANUP:
	// save old values into the new ones and release the others
	ReleaseColumnDesc(rgOldCD, nOldlen);
	ReleaseColumnDesc(rgNewCD, nNewlen);
	ReleaseColumnDesc(pOriginalColumnDesc, 1);
	return hr;
} //TCITableDefinition::AddColumnAndCheck




//---------------------------------------------------------------------
//
// @member Create the table using ITableDefinition::CreateTable and 
// check its creation
//---------------------------------------------------------------------
HRESULT TCITableDefinition::CreateAndCheckTable(
	ITableDefinition	*pITableDefinition,	// [in] pointer to the ITableDefinition interface to be used
	IUnknown			*pUnkOuter,			// [in] pointer to controlling unknown
	DBID				*pTableID,			// [in]	pointer to the input table ID
	DBORDINAL			cColumnDescs,		// [in]	the number of columns to be created
	DBCOLUMNDESC		*rgColumnDescs,		// [in/out] array of columns to be created
	REFIID				riid,				// [in] rowset interface to be returned
	ULONG				cPropertySets,		// [in] number of roset property sets asked
	DBPROPSET			*rgPropertySets,	// [in/out] array of rowset property sets
	DBID				**ppTableID,		// [out] returned table ID
	IUnknown			**ppRowset			// [out] pointer to outer interface
)
{
	BOOL				fExists;
	DBORDINAL			cOriginalColumnDescs = 0;
	DBCOLUMNDESC		*rgOriginalColumnDescs = NULL;
	ULONG				cOriginalPropertySets = 0;
	DBPROPSET			*rgOriginalPropertySets = NULL;
	HRESULT				hres;
	DBID				*pNewTableID = NULL;
	CTable				*pTable = new CTable(pITableDefinition, (LPWSTR)gwszModuleName);
	IUnknown			*pIUnknown = NULL; // used to pass the rowset pointer to AreColumnsCreatedOK

	ASSERT(pTable);
	ASSERT(pITableDefinition);
	
	// save the original values 
	CHECK(0 == cColumnDescs || NULL == rgColumnDescs
		|| NULL != DuplicateColumnDesc(rgColumnDescs, cColumnDescs, &rgOriginalColumnDescs), TRUE);
	cOriginalColumnDescs = cColumnDescs;
	CHECK(0 == cPropertySets || NULL == rgPropertySets 
		|| DuplicatePropertySets(cPropertySets, rgPropertySets, &cOriginalPropertySets, &rgOriginalPropertySets), TRUE);

	// go for ITableDefinition::CreateTable
	hres = pITableDefinition->CreateTable(pUnkOuter, pTableID, cColumnDescs, rgColumnDescs, riid, 
		cPropertySets, rgPropertySets, ppTableID, ppRowset);

	if (SUCCEEDED(hres))
	{
		COMPARE(NULL == ppTableID || NULL != *ppTableID, TRUE);
	}
	else
	{
		COMPARE(NULL == ppTableID || NULL == *ppTableID, TRUE);
	}

	if (rgOriginalColumnDescs 
		&& !COMPARE(IsColumnDescPreserved(rgOriginalColumnDescs, rgColumnDescs, cColumnDescs), TRUE))
	{
		odtLog << "\tERROR: array of column desc is not preserved\n";
	}

	if (	rgOriginalPropertySets
		&&	!COMPARE(IsRowsetPropSetPreserved(rgOriginalPropertySets, rgPropertySets, cPropertySets), TRUE))
	{
		odtLog << "\tERROR: the rowset property sets are not preserved\n";
	}

	COMPARE(CheckRwstTblPropStatus(cPropertySets, rgPropertySets, hres), TRUE);
	COMPARE(CheckColPropStatus(cColumnDescs, rgColumnDescs, hres), TRUE);

	pNewTableID = (ppTableID)? (*ppTableID): pTableID;

	// if the table creation was reported as succeding, the table should exist
	if (	SUCCEEDED(hres) 
		&&	(!CHECK(pTable->DoesTableExist(pNewTableID, &fExists), S_OK) || !fExists))
	{
		if (!fExists)
			odtLog << "\tERROR: despite the return value reported, the table doesn't exist\n";
	}

	// if the table creation was reported as failed, the table should not exist
	if (	FAILED(hres) 
		&&	DB_E_DUPLICATETABLEID != hres 
		&&	DB_E_NOTABLE != hres
		&&	pNewTableID
		&&	(!CHECK(pTable->DoesTableExist(pNewTableID, &fExists), S_OK) || fExists))
	{
		if (!fExists)
			odtLog << "\tERROR: despite the return value reported, the table exists\n";
	}

	if (SUCCEEDED(hres))
	{
		pIUnknown = (ppRowset) ? (IUnknown*)(*ppRowset) : NULL;
		COMPARE(AreColumnsCreatedOK(rgColumnDescs, cColumnDescs, pNewTableID, pIUnknown), TRUE);

		if (ppRowset)
		{
			COMPARE(IsRowsetPropSetCreatedOK(rgPropertySets, cPropertySets, *ppRowset), TRUE);
			COMPARE(!ppRowset || CheckRowset(*ppRowset), TRUE);
		}
		COMPARE(CheckReturnedDBID(pTableID, ppTableID), TRUE);
	}
	else
	{
		COMPARE(ppRowset && NULL == *ppRowset, TRUE);
		COMPARE(!ppTableID || NULL == *ppTableID, TRUE);
	}
	
	delete pTable;
	ReleaseColumnDesc(rgOriginalColumnDescs, cOriginalColumnDescs);
	FreeProperties( &cOriginalPropertySets, &rgOriginalPropertySets);
	return hres;
} //TCITableDefinition::CreateAndCheckTable



						
//---------------------------------------------------------------------
//
// @member Create the table using ITableDefinitionWithConstraints::CreateTableWithConstraints and 
// check its creation
//---------------------------------------------------------------------
HRESULT TCITableDefinition::CreateAndCheckTableWithConstraints(
		ITableDefinitionWithConstraints		*pITableDefinitionWithConstraints,	// [in] pointer to the ITableDefinitionWithConstraints interface to be used
		IUnknown							*pUnkOuter,			// [in] pointer to controlling unknown
		DBID								*pTableID,			// [in]	pointer to the input table ID
		DBORDINAL							cColumnDescs,		// [in]	the number of columns to be created
		DBCOLUMNDESC						*rgColumnDescs,		// [in/out] array of columns to be created
		ULONG								cConstraintDescs,	// [in]	the number of constraints to be created
		DBCONSTRAINTDESC					*rgConstraintDescs,	// [in/out] array of constraints
		REFIID								riid,				// [in] rowset interface to be returned
		ULONG								cPropertySets,		// [in] number of roset property sets asked
		DBPROPSET							*rgPropertySets,	// [in/out] array of rowset property sets
		DBID								**ppTableID,		// [out] returned table ID
		IUnknown							**ppRowset			// [out] pointer to outer interface
)
{
	BOOL				fExists;
	DBORDINAL			cOriginalColumnDescs = 0;
	DBCOLUMNDESC		*rgOriginalColumnDescs = NULL;
	ULONG				cOriginalPropertySets = 0;
	DBPROPSET			*rgOriginalPropertySets = NULL;
	HRESULT				hres;
	DBID				*pNewTableID = NULL;
	CTable				*pTable = new CTable(pITableDefinitionWithConstraints, (LPWSTR)gwszModuleName);
	IUnknown			*pIUnknown = NULL; // used to pass the rowset pointer to AreColumnsCreatedOK
	CConstraints		Constraints(pITableDefinitionWithConstraints);
	DBORDINAL			index;

	ASSERT(pTable);
	ASSERT(pITableDefinitionWithConstraints);
	
	// save the original values 
	CHECK(0 == cColumnDescs || NULL == rgColumnDescs
		|| NULL != DuplicateColumnDesc(rgColumnDescs, cColumnDescs, &rgOriginalColumnDescs), TRUE);
	cOriginalColumnDescs = cColumnDescs;
	CHECK(0 == cPropertySets || NULL == rgPropertySets 
		|| DuplicatePropertySets(cPropertySets, rgPropertySets, &cOriginalPropertySets, &rgOriginalPropertySets), TRUE);

	// get original constraint set
	if (pTableID && (DBKIND_NAME == pTableID->eKind) && pTableID->uName.pwszName)
	{
		CHECK(Constraints.GetConstraints(NULL, NULL, pTableID->uName.pwszName, NULL, NULL, NULL), S_OK);
	}

	// go for ITableDefinition::CreateTable
	hres = pITableDefinitionWithConstraints->CreateTableWithConstraints(pUnkOuter, 
		pTableID, cColumnDescs, rgColumnDescs, cConstraintDescs, rgConstraintDescs,
		riid, cPropertySets, rgPropertySets, ppTableID, ppRowset);

	if (	rgOriginalColumnDescs
		&&	!COMPARE(IsColumnDescPreserved(rgOriginalColumnDescs, rgColumnDescs, cColumnDescs), TRUE))
	{
		odtLog << "\tERROR: array of column desc is not preserved\n";
	}

	if (	rgOriginalPropertySets
		&&	!COMPARE(IsRowsetPropSetPreserved(rgOriginalPropertySets, rgPropertySets, cPropertySets), TRUE))
	{
		odtLog << "\tERROR: the rowset property sets are not preserved\n";
	}

	COMPARE(CheckRwstTblPropStatus(cPropertySets, rgPropertySets, hres), TRUE);
	COMPARE(CheckColPropStatus(cColumnDescs, rgColumnDescs, hres), TRUE);

	pNewTableID = (ppTableID)? (*ppTableID): pTableID;

	// if the table creation was reported as succeding, the table should exist
	if (	SUCCEEDED(hres) 
		&&	(!CHECK(pTable->DoesTableExist(pNewTableID, &fExists), S_OK) || !fExists))
	{
		if (!fExists)
			odtLog << "\tERROR: despite the return value reported, the table doesn't exist\n";
	}

	// if the table creation was reported as failed, the table should not exist
	if (	FAILED(hres) 
		&&	DB_E_DUPLICATETABLEID != hres 
		&&	DB_E_NOTABLE != hres
		&&	pNewTableID
		&&	(!CHECK(pTable->DoesTableExist(pNewTableID, &fExists), S_OK) || fExists))
	{
		if (!fExists)
			odtLog << "\tERROR: despite the return value reported, the table exists\n";
	}


	if (SUCCEEDED(hres))
	{
		pIUnknown = (ppRowset) ? (IUnknown*)(*ppRowset) : NULL;
		COMPARE(AreColumnsCreatedOK(rgColumnDescs, cColumnDescs, pNewTableID, pIUnknown), TRUE);
		if (ppRowset)
		{
			COMPARE(IsRowsetPropSetCreatedOK(rgPropertySets, cPropertySets, *ppRowset), TRUE);
			COMPARE(!ppRowset || CheckRowset(*ppRowset), TRUE);
		}
		COMPARE(CheckReturnedDBID(pTableID, ppTableID), TRUE);

		// check constraint creation
		if (pNewTableID && (DBKIND_NAME == pNewTableID->eKind) && pNewTableID->uName.pwszName)
		{
			CHECK(Constraints.GetConstraints(NULL, NULL, pNewTableID->uName.pwszName, NULL, NULL, NULL), S_OK);
			// the number of constraints created is greater than or equal to cConstraintDescs
			// this happens because the user can ask for some more constraints using column props
			COMPARE(Constraints.GetConstrNo() >= cConstraintDescs, TRUE);

			for (index = 0; index < cConstraintDescs; index++)
			{
				// BEWARE: if deferred flag was set without deferrable 
				// flag being set, constraint should be immediate
				if (rgConstraintDescs[index].Deferrability == DBDEFERRABILITY_DEFERRABLE)
					rgConstraintDescs[index].Deferrability = 0;
			}
	
			CHECK(Constraints.CheckIncludedConstraints(cConstraintDescs, rgConstraintDescs), S_OK);
		}
	}
	else
	{
		COMPARE(NULL == ppRowset || NULL == *ppRowset, TRUE);
		COMPARE(NULL == ppTableID || NULL == *ppTableID, TRUE);

		// check no constraints existed on the table 
		if (DB_E_DUPLICATETABLEID == hres)
		{
			CHECK(Constraints.AreConstraintsPreserved(), S_OK);
		}
		else
		{
			// make sure no constraints exist for this table name (if not invalid)
			if (pTableID && (DBKIND_NAME == pTableID->eKind) && pTableID->uName.pwszName)
			{
				CHECK(Constraints.GetConstraints(NULL, NULL, pTableID->uName.pwszName, NULL, NULL, NULL), S_OK);
				COMPARE(Constraints.GetConstrNo(), 0);
			}
		}
	}
	
	delete pTable;

	ReleaseColumnDesc(rgOriginalColumnDescs, cOriginalColumnDescs);
	FreeProperties( &cOriginalPropertySets, &rgOriginalPropertySets);
	return hres;
} //TCITableDefinition::CreateAndCheckTableWithConstraints




// Add a constraint to a table using ITableDefinitionWithConstraints::AddConstraint and check its creation
HRESULT	TCITableDefinition::AddConstraintAndCheck(
	ITableDefinitionWithConstraints		*pITableDefinitionWithConstraints,	// [in] pointer to the ITableDefinitionWithConstraints interface to be used
	DBID								*pTableID,							// [in]	pointer to the input table ID
	DBCONSTRAINTDESC					*pConstraintDesc,					// [in] new constraint
	BOOL								fDifferentColTypesInFK
)
{
	// this method assumes that the table indicated by pTableID does exist
	HRESULT			hr				= E_FAIL;
	HRESULT			rgValidHRes[]	= {	S_OK,
										E_FAIL,
										E_INVALIDARG,
										DB_E_DUPLICATECONSTRAINTID,
										DB_E_BADCONSTRAINTID,
										DB_E_BADCONSTRAINTTYPE,
										DB_E_BADUPDATEDELETERULE,
										DB_E_BADMATCHTYPE,
										DB_E_BADDEFERRABILITY,
										DB_E_BADCONSTRAINTFORM,
										DB_E_NOCOLUMN,
										DB_E_NOTABLE,
										DB_E_TABLEINUSE,
										DB_SEC_E_PERMISSIONDENIED,
										XACT_E_XTIONEXISTS,
							            DB_E_SCHEMAVIOLATION
									}; 
	ULONG			cValidHRes = NUMELEM(rgValidHRes);
	CConstraints	Constraints(pITableDefinitionWithConstraints);
	DBID			*pConstraintID;
	ULONG			index;

	// keep trace of whether the constraint DBID was NULL
	pConstraintID = pConstraintDesc? pConstraintDesc->pConstraintID: NULL;

	TESTC(NULL != pITableDefinitionWithConstraints);

	// get all the constraints associated with the table
	if (pTableID && DBKIND_NAME == pTableID->eKind)
	{
		TESTC_(Constraints.GetConstraints(NULL, NULL, pTableID->uName.pwszName, NULL, NULL, NULL), S_OK);
	}
	else
	{
		TESTC_(Constraints.GetConstraints(NULL, NULL, NULL, NULL, NULL, NULL), S_OK);
	}
	
	hr = pITableDefinitionWithConstraints->AddConstraint(pTableID, pConstraintDesc);

	// check that constraint ID is not modified if set to NULL
	COMPARE(!pConstraintDesc || (pConstraintID == pConstraintDesc->pConstraintID), TRUE);

	// check that the result is one of the expected results
	TESTC(CheckResult(hr, cValidHRes, rgValidHRes));

	if (FAILED(hr))
	{
			CHECK(Constraints.AreConstraintsPreserved(), S_OK);
	}
	else
	{
		TESTC(NULL != pTableID);
		// check that the constraint was added
		DBDEFERRABILITY		def = pConstraintDesc->Deferrability;
		// BEWARE: if deferred flag was set without deferrable 
		// flag being set, constraint should be immediate
		if (pConstraintDesc->Deferrability == DBDEFERRABILITY_DEFERRABLE)
			pConstraintDesc->Deferrability = 0;
		CHECK(Constraints.CheckAddConstraints(1, pConstraintDesc), S_OK);
		pConstraintDesc->Deferrability = def;
	}

	switch (hr)
	{
		case S_OK:
			break;

		case E_INVALIDARG:
			// check the returned value condition (assume only one of them was set, if any)
			TESTC(	NULL == pTableID || NULL == pConstraintDesc 
			||	0 < pConstraintDesc->cForeignKeyColumns && NULL == pConstraintDesc->rgForeignKeyColumnList
			||	0 < pConstraintDesc->cForeignKeyColumns && pConstraintDesc->cColumns != pConstraintDesc->cForeignKeyColumns
			||	0 < pConstraintDesc->cColumns && NULL == pConstraintDesc->rgColumnList
			||	0 != pConstraintDesc->cReserved && NULL == pConstraintDesc->rgReserved);
			break;

		case DB_E_BADCONSTRAINTID:
			// conditions for DB_E_BADCONSTRAINTID
			break;

		case DB_E_DUPLICATECONSTRAINTID:
			// condition for DB_E_DUPLICATECONSTRAINTID
			if (	(NULL == Constraints[pConstraintDesc->pConstraintID])
				&&	(pTableID && DBKIND_NAME == pTableID->eKind))
			{
				DBCONSTRAINTDESC	*pConstraintDesc = Constraints.GetConstraints();

				// or there is a primary constraint on this table
				for (index = 0; index < Constraints.GetConstrNo(); index++)
				{
					if (DBCONSTRAINTTYPE_PRIMARYKEY == pConstraintDesc->ConstraintType)
						break;
				}
				TESTC(index < Constraints.GetConstrNo());
			}
			break;

		case DB_E_BADCONSTRAINTTYPE:
			// condition for DB_E_BADCONSTRAINTTYPE: ConstraintType was invalid or not supported by the provider
			TESTC(DBCONSTRAINTTYPE_UNIQUE != pConstraintDesc->ConstraintType);
			TESTC(DBCONSTRAINTTYPE_PRIMARYKEY != pConstraintDesc->ConstraintType);

			TESTC(DBCONSTRAINTTYPE_FOREIGNKEY != pConstraintDesc->ConstraintType);

			TESTC(DBCONSTRAINTTYPE_CHECK != pConstraintDesc->ConstraintType);
			break;

		case DB_E_BADUPDATEDELETERULE:
			TESTC(DBCONSTRAINTTYPE_FOREIGNKEY == pConstraintDesc->ConstraintType);
			break;

		case DB_E_BADMATCHTYPE:
			break;

		case DB_E_BADDEFERRABILITY:
			break;

		case DB_E_BADCONSTRAINTFORM:
			if (!(		DBCONSTRAINTTYPE_FOREIGNKEY != pConstraintDesc->ConstraintType
					&& (0 < pConstraintDesc->cForeignKeyColumns || NULL != pConstraintDesc->pReferencedTableID)
				||	DBCONSTRAINTTYPE_CHECK == pConstraintDesc->ConstraintType && NULL == pConstraintDesc->pwszConstraintText
				||	DBCONSTRAINTTYPE_CHECK == pConstraintDesc->ConstraintType && 0 != pConstraintDesc->cColumns
				||	DBCONSTRAINTTYPE_CHECK != pConstraintDesc->ConstraintType && NULL != pConstraintDesc->pwszConstraintText
				||	DBCONSTRAINTTYPE_FOREIGNKEY == pConstraintDesc->ConstraintType && 0 == pConstraintDesc->cForeignKeyColumns
				||	(	DBCONSTRAINTTYPE_FOREIGNKEY == pConstraintDesc->ConstraintType
					||	DBCONSTRAINTTYPE_PRIMARYKEY == pConstraintDesc->ConstraintType
					||	DBCONSTRAINTTYPE_UNIQUE == pConstraintDesc->ConstraintType) && 0 == pConstraintDesc->cColumns
				||	DBCONSTRAINTTYPE_FOREIGNKEY == pConstraintDesc->ConstraintType && NULL == pConstraintDesc->pReferencedTableID 
				))
			{
				// the only good alternative is that the columns in the referenced table and
				// and the ones in the base table have different types
				TESTC(fDifferentColTypesInFK);
			}
			// Note: the case when the column types of corresponding cols do not match in a FK is missing!
			break;

		case DB_E_NOCOLUMN:
			// check that one of the columns referred does not exist in the table
			// (either col in the base table or col in the referenced table for FK)
			break;

		case DB_E_NOTABLE:
			// pReferencedTableID (for foreign keys) or pTableID does not exist
			break;

		case DB_E_TABLEINUSE:
		case DB_SEC_E_PERMISSIONDENIED:
        case DB_E_SCHEMAVIOLATION:
		case XACT_E_XTIONEXISTS:
			break;

		case E_FAIL:
			// this code is legal; caller should catch it if there
			// is a more meaningful return value
			break;

		default:
			TESTC(FALSE);
	};

CLEANUP:
	return hr;
} //TCITableDefinition::AddConstraintAndCheck




//---------------------------------------------------------------------
//
// Drop a constraint to a table using ITableDefinitionWithConstraints::DropConstraint and check its deletion
HRESULT	TCITableDefinition::DropConstraintAndCheck(
	ITableDefinitionWithConstraints		*pITableDefinitionWithConstraints,	// [in] pointer to the ITableDefinitionWithConstraints interface to be used
	DBID								*pTableID,							// [in]	pointer to the input table ID
	DBID								*pConstraintID						// [in] pointer to the DBID of the constraint
)
{
	HRESULT			hr = E_FAIL;
	HRESULT			rgValidHRes[]	= {	S_OK,
										E_FAIL,
										E_INVALIDARG,
										DB_E_NOCONSTRAINT,
										DB_E_BADTABLEID,
										DB_E_DROPRESTRICTED,
										DB_E_NOTABLE,
										DB_E_TABLEINUSE,
										DB_SEC_E_PERMISSIONDENIED,
										XACT_E_XTIONEXISTS,
							            DB_E_SCHEMAVIOLATION
									}; 
	DBORDINAL		ulInitConstraints = 0;

	ULONG			cValidHRes = NUMELEM(rgValidHRes);
	CConstraints	Constraints(pITableDefinitionWithConstraints);

	TESTC(NULL != pITableDefinitionWithConstraints);

	// get all the constraints associated with the table
	if (pTableID && DBKIND_NAME == pTableID->eKind)
	{
		CHECK(Constraints.GetConstraints(NULL, NULL, pTableID->uName.pwszName, NULL, NULL, NULL), S_OK);
		ulInitConstraints = Constraints.GetConstrNo();
	}
	else
	{
		CHECK(Constraints.GetConstraints(NULL, NULL, NULL, NULL, NULL, NULL), S_OK);
	}

	// drop the constraint
	hr = pITableDefinitionWithConstraints->DropConstraint(pTableID, pConstraintID);


	// check that the result is one of the expected results
	COMPARE(CheckResult(hr, cValidHRes, rgValidHRes), TRUE);

	if (FAILED(hr))
	{
			CHECK(Constraints.AreConstraintsPreserved(), S_OK);
	}
	else
	{
		// check that the constraint was dropped
		if (NULL != pTableID && DBKIND_NAME == pTableID->eKind)
		{
			CConstraints	NewConstraints(pITableDefinitionWithConstraints);
			
			CHECK(NewConstraints.GetConstraints(NULL, NULL, pTableID->uName.pwszName, NULL, NULL, NULL), S_OK);
			COMPARE(NULL == NewConstraints[pConstraintID], TRUE);
			COMPARE(ulInitConstraints-1, NewConstraints.GetConstrNo());
			CHECK(Constraints.CheckIncludedConstraints(NewConstraints.GetConstrNo(),
				NewConstraints.GetConstraints()), S_OK);
		}

	}

CLEANUP:
	return hr;
} //TCITableDefinition::DropConstraintAndCheck




//---------------------------------------------------------------------
//
// @member Create the table using ITableDefinition::CreateTable, 
// check its creation then drops the table and releases the rowset interface
//---------------------------------------------------------------------
HRESULT TCITableDefinition::CCNDropTable(
	DBID			*pTableID,			// [in]	pointer to the input table ID
	DBORDINAL		cColumnDescs,		// [in]	the number of columns to be created
	DBCOLUMNDESC	*rgColumnDescs,		// [in/out] array of columns to be created
	REFIID			riid,				// [in] rowset interface to be returned
	ULONG			cPropertySets,		// [in] number of roset property sets asked
	DBPROPSET		*rgPropertySets,	// [in/out] array of rowset property sets
	BOOL			fNullPPTableID/*=FALSE*/	// [in] if TRUE ppTableID will be NULL
)
{
	HRESULT		hr;
	BOOL		fExists;
	DBID		*pNewTableID	= NULL;
	DBID		*pOutTableID	= NULL;		// [out] returned table ID
	DBID		**ppTableID		= fNullPPTableID? NULL: &pOutTableID;
	IUnknown	*pRowset		= NULL;		// [out] pointer to outer interface
	CTable		*pTable			= new CTable(m_pITableDefinition, (LPWSTR)gwszModuleName);

	hr = CreateAndCheckTable(m_pITableDefinition, NULL, pTableID, cColumnDescs, rgColumnDescs, riid, 
		cPropertySets, rgPropertySets, ppTableID, &pRowset);

	SAFE_RELEASE(pRowset);

	pNewTableID = (ppTableID)? *ppTableID: pTableID;
	if (	pNewTableID
		&&	DB_E_NOTABLE != hr
		&&	DB_E_DUPLICATETABLEID != hr
		&&	CHECK(pTable->DoesTableExist(pNewTableID, &fExists), S_OK)
		&&	fExists)
		CHECK(m_pITableDefinition->DropTable(pNewTableID), S_OK);
	
	delete pTable;
	ReleaseDBID(pOutTableID);
	return hr;
} //TCITableDefinition::CCNDropTable




//--------------------------------------------------------------------------
//
// @cmember Check whether the columns were properly created
// The columns of the m_pTable are checked against the column descriptor array <nl>
// returned by ITableDefinition::CreateTable method. 
//	RETURNS
//		TRUE	- everything is created ok
//		FALSE	- errors
//--------------------------------------------------------------------------
BOOL TCITableDefinition::AreColumnsCreatedOK(
	DBCOLUMNDESC	*rgOutColumnDesc,	// [in] the aray returned by ITableDefinition::CreateTable
	DBORDINAL		cColumnDesc,		// [in] the size of the arrays
	DBID			*pTableID/*=NULL*/,	// [in] Table ID
	IUnknown		*pIUnknown/*=NULL*/	// [in] pointer to a rowset interface on the table
)
{
	DBORDINAL		cCDFromTable;
	BOOL			fTestRes		= TRUE;
	DBCOLUMNDESC	*rgCDFromTable	= NULL;
	ULONG			i;
	CTable			*pTable = new CTable(m_pThisTestModule->m_pIUnknown2, (LPWSTR)gwszModuleName);

	// get the descriptions of the columns in the table with DBID == m_pTable->GetTableID()
	// the list of columns are stored in m_pTable->m_colList
	GetColumnDescOnTable(pTableID? pTableID: &m_pTable->GetTableID(), 
		&rgCDFromTable, &cCDFromTable);

	if (cColumnDesc != cCDFromTable)
	{
		odtLog << "the number of columns asked and created does not fit";
		fTestRes = FALSE;
		goto CLEANUP;
	}

	for (i=0; i<cColumnDesc; i++)
	{
		fTestRes = fTestRes && CompareColumnDesc(&rgOutColumnDesc[i], &rgCDFromTable[i]);
	}
	
CLEANUP:
	ReleaseColumnDesc(rgCDFromTable, cCDFromTable);
	delete pTable;
	return fTestRes;
} //TCITableDefinition::AreColumnsCreatedOK




//--------------------------------------------------------------------
//
// @member Check properties on rowseet and table
//	returns TRUE if the prop set is set correctly
//			FALSE otherwise
//--------------------------------------------------------------------
BOOL TCITableDefinition::CheckRwstTblPropStatus(
	ULONG			cPropSets,			// [in] the size of the propset array
	DBPROPSET		*rgPropSets,		// [in] propset array
	HRESULT			hr					// [in]	the result of the previous op
)
{
	GUID	guidExpectedPS;
	ULONG	cPropSet;
	ULONG	cProp;
	BOOL	fRes = TRUE;

	if (!rgPropSets)
		return TRUE;

	for (cPropSet = 0; cPropSet < cPropSets; cPropSet++)
	{
		if (!rgPropSets[cPropSet].rgProperties)
			continue;
		guidExpectedPS = rgPropSets[cPropSet].guidPropertySet == DBPROPSET_ROWSET? DBPROPSET_ROWSET: DBPROPSET_TABLE;
		for (cProp = 0; cProp < rgPropSets[cPropSet].cProperties; cProp++)
		{
			fRes = fRes && CheckPropertyStatus(rgPropSets[cPropSet].guidPropertySet, guidExpectedPS,
				&rgPropSets[cPropSet].rgProperties[cProp], hr);
		}
	}
	return fRes;
} //TCITableDefinition::CheckRwstTblPropStatus
	



//--------------------------------------------------------------------------
//
// @cmember Check whether the property sets asked for rowset was preserved
// all the data should be inside, the only thing that is allowed to be modified <nl>
// is the property status
//--------------------------------------------------------------------------
BOOL TCITableDefinition::IsRowsetPropSetPreserved
(
	DBPROPSET	*rgInPropertySets,	// the array passed to ITableDefinition::CreateTable
	DBPROPSET	*rgOutPropertySets,	// the aray returned by ITableDefinition::CreateTable
	ULONG		cPropertySets			// the size of the arrays
)
{
	ULONG	ps, pc;
	
	if (NULL == rgInPropertySets)
		return TRUE;
	for (ps=0; ps<cPropertySets; ps++)
	{
		// compare the props in that prop set
		if (!CHECK(rgInPropertySets[ps].guidPropertySet == rgOutPropertySets[ps].guidPropertySet, TRUE))
			return FALSE;
		if (!CHECK(rgInPropertySets[ps].cProperties == rgOutPropertySets[ps].cProperties, TRUE))
			return FALSE;
		if (NULL == rgInPropertySets[ps].rgProperties)
			continue;

		for (pc=0; pc<rgInPropertySets[ps].cProperties; pc++)
		{
			if (!CHECK(rgInPropertySets[ps].rgProperties[pc].dwPropertyID == 
					   rgOutPropertySets[ps].rgProperties[pc].dwPropertyID, TRUE))
				return FALSE;
			if (!CHECK(rgInPropertySets[ps].rgProperties[pc].dwOptions == 
					   rgOutPropertySets[ps].rgProperties[pc].dwOptions, TRUE))
				return FALSE;
			// use NULL for DSO interface
			if (!COMPARE(CompareDBID(rgInPropertySets[ps].rgProperties[pc].colid, 
					   rgOutPropertySets[ps].rgProperties[pc].colid,
					   NULL), TRUE))
				return FALSE;
			if (!COMPARE(CompareVariant(&rgInPropertySets[ps].rgProperties[pc].vValue,
					   &rgOutPropertySets[ps].rgProperties[pc].vValue), TRUE))
				return FALSE;
		}
	}
	return TRUE;
} //TCITableDefinition::IsRowsetPropSetPreserved

						


//--------------------------------------------------------------------------
//
// @cmember Check whether the rowset properties were properly created
// The rowset properties of the m_pTable are checked against the property set<nl>
// returned by ITableDefinition::CreateTable method. 
//--------------------------------------------------------------------------
BOOL TCITableDefinition::IsRowsetPropSetCreatedOK
(
	DBPROPSET	*rgOutPropertySets,		// the aray returned by ITableDefinition::CreateTable
	ULONG		cPropertySets,			// the size of the arrays
	IUnknown	*pIUnknown				// pointer to the rowset interface
)
{
	IRowsetInfo		*pIRowsetInfo = NULL;
	DBPROPIDSET		*rgPropIDSet = NULL;
	DBPROPSET		*rgPropertySets = NULL;
	ULONG			n;
	BOOL			fTestRes = TEST_PASS;
	DBPROPSTATUS	ulStatus;
	DBPROPOPTIONS	ulOption;
	DBPROPID		ulPropID;
	BOOL			fSupported;
	BOOL			fSettable;
	VARIANT			*pvValue;
	
	if (!pIUnknown || 0 == cPropertySets || !rgOutPropertySets)
		return TRUE;

	rgPropIDSet = (DBPROPIDSET*) PROVIDER_ALLOC(sizeof(DBPROPIDSET)*cPropertySets);
	for (n=0; n<cPropertySets; n++)
	{
		// get propID in the property set 
		rgPropIDSet[n].guidPropertySet	= rgOutPropertySets[n].guidPropertySet;
		rgPropIDSet[n].cPropertyIDs		= rgOutPropertySets[n].cProperties;
		if (0 == rgOutPropertySets[n].rgProperties)
		{
			rgPropIDSet[n].rgPropertyIDs = NULL;
			continue;
		}
		else
			SAFE_ALLOC(rgPropIDSet[n].rgPropertyIDs, DBPROPID, rgOutPropertySets[n].cProperties);
		for (ULONG i=0; i<rgOutPropertySets[n].cProperties; i++)
		{
			rgPropIDSet[n].rgPropertyIDs[i] = rgOutPropertySets[n].rgProperties[i].dwPropertyID;
		}
	}
	// get the properties of the rowset
	if (!VerifyInterface(pIUnknown, IID_IRowsetInfo, ROWSET_INTERFACE, (IUnknown**)&pIRowsetInfo))
	{
		fTestRes = TEST_FAIL;
		goto CLEANUP;
	}
	else
	{
		m_hr = pIRowsetInfo->GetProperties(cPropertySets, rgPropIDSet, &n, &rgPropertySets);
		ASSERT(n==cPropertySets);
	}

	if (NULL == rgPropertySets)
	{
		fTestRes = TEST_FAIL;
		goto CLEANUP;
	}
	// check the properties
	for (n=0; n<cPropertySets; n++)
	{
		// get propID in the property set 
		if (DBPROPSET_TABLE == rgOutPropertySets[n].guidPropertySet)
			continue;
		if (0 == rgOutPropertySets[n].cProperties)
			continue;
		if (rgPropertySets[n].cProperties != rgOutPropertySets[n].cProperties)
			fTestRes = TEST_FAIL;
		if (NULL == rgOutPropertySets[n].rgProperties)
			continue;
		if (NULL == rgPropertySets[n].rgProperties)
		{
			fTestRes = TEST_FAIL;
			continue;
		}
		// check dbpropstatus
		if (!CHECK(DBPROPSET_ROWSET == rgOutPropertySets[n].guidPropertySet, TRUE))
		{
			for (ULONG i=0; i<rgOutPropertySets[n].cProperties; i++)
				if (!COMPARE(rgOutPropertySets[n].rgProperties[i].dwStatus, DBPROPSTATUS_NOTSUPPORTED))
					fTestRes = TEST_FAIL;
			continue;
		}

		for (ULONG i=0; i<rgOutPropertySets[n].cProperties; i++)
		{
			ulPropID	= rgOutPropertySets[n].rgProperties[i].dwPropertyID;
			ulOption	= rgOutPropertySets[n].rgProperties[i].dwStatus;
			ulStatus	= rgOutPropertySets[n].rgProperties[i].dwOptions;
			fSupported	= SupportedProperty(ulPropID, DBPROPSET_ROWSET);
			fSettable	= SettableProperty(ulPropID, DBPROPSET_ROWSET);
			pvValue		= &rgOutPropertySets[n].rgProperties[i].vValue;
	
			if (!fSupported)
			{
				fTestRes = DBPROPSTATUS_NOTSUPPORTED == ulStatus? fTestRes : TEST_FAIL;
				continue;
			}

			// property is supported => cannot be sure that setting a prop will fail
			// if is settable, the prop should succeed, unless a bad value is tried
			if (DBPROPSTATUS_OK == ulStatus)
			{
				if (ulPropID != rgOutPropertySets[n].rgProperties[i].dwPropertyID)
					fTestRes = TEST_FAIL;
				if (!CompareVariant(pvValue, &rgOutPropertySets[n].rgProperties[i].vValue))
				{
					fTestRes = TEST_FAIL;
					odtLog	<< "Rowset property values missmatch for property propID("
							<< rgOutPropertySets[n].rgProperties[i].dwPropertyID << ")\n";
				}
			}

			switch (ulStatus)
			{
				case DBPROPSTATUS_CONFLICTING:
					fTestRes = (DBPROPOPTIONS_OPTIONAL == ulOption || DBPROPOPTIONS_REQUIRED == ulOption)
						&& pvValue->vt == GetPropInfoType(ulPropID, DBPROPSET_ROWSET)? fTestRes : TEST_FAIL;
					break;
				case DBPROPSTATUS_NOTSET:
					fTestRes = COMPARE(ulOption, DBPROPOPTIONS_OPTIONAL)
						&& pvValue->vt == GetPropInfoType(ulPropID, DBPROPSET_ROWSET)? fTestRes : TEST_FAIL;
					break;
				case DBPROPSTATUS_BADOPTION:
					fTestRes =		(DBPROPOPTIONS_OPTIONAL != ulOption) 
								&&	(DBPROPOPTIONS_REQUIRED)? fTestRes : TEST_FAIL;
					break;
				case DBPROPSTATUS_NOTSETTABLE:
					fTestRes = !fSettable? fTestRes: TEST_FAIL;
					break;
				case DBPROPSTATUS_BADVALUE:
					fTestRes = (VT_EMPTY != pvValue->vt)
						&& (pvValue->vt != GetPropInfoType(ulPropID, DBPROPSET_ROWSET))
						? fTestRes : TEST_FAIL;
			}
		}
	}

CLEANUP:
	SAFE_RELEASE(pIRowsetInfo);
	for (n=0; n<cPropertySets; n++)
		PROVIDER_FREE(rgPropIDSet[n].rgPropertyIDs);
	PROVIDER_FREE(rgPropIDSet);
	FreeProperties( &cPropertySets, &rgPropertySets);
	return fTestRes;
} //TCITableDefinition::IsRowsetPropSetCreatedOK



//--------------------------------------------------------------------------
//
// @cmember Creates a table with a column of each provider type and returns a rowset
// to the new created table. The rowset is created with the property required and it
// is tested
//--------------------------------------------------------------------------
int	TCITableDefinition::CreateWithOneRowsetProps
(
	DBPROPID		PropID,				// Property ID
	DBTYPE			DBType,				// type of property value
	LPVOID			Value,				// value to be set
	struct _GUID	*pRIID				// interface asked on rowset
)
{
	DBTYPE			rgDBTypes[]		= {DBType};
	LPVOID			rgValues[]		= {Value};
	DBPROPOPTIONS	rgOptions[]		= {DBPROPOPTIONS_OPTIONAL};
	DBPROPOPTIONS	rgOptions2[]	= {DBPROPOPTIONS_REQUIRED};


	return	CreateWithRowsetProps(1, &PropID, rgDBTypes, rgValues, rgOptions, pRIID)
		&&	CreateWithRowsetProps(1, &PropID, rgDBTypes, rgValues, rgOptions2, pRIID);
} //TCITableDefinition::CreateWithOneRowsetProps

	



//--------------------------------------------------------------------------
//
// @cmember Creates a table with a column of each provider type and returns a rowset
// to the new created table. The rowset is created with the properties required and it
// is tested
//--------------------------------------------------------------------------
BOOL TCITableDefinition::CreateWithRowsetProps
(
	ULONG			nProperties,			// number of the properties to be set
	DBPROPID		*rgPropID,				// array with the propIDs
	DBTYPE			*rgDBType,				// type of property values			
	LPVOID			*rgValue,				// values to be set
	DBPROPOPTIONS	*rgOptions,				// options of properties
	struct _GUID	*pRIID					// interface asked on rowset
)
{
	BOOL			fRes			= FALSE;
	DBPROPSET		*rgPropertySets = NULL;
	ULONG			n, cPropertySets = 0;
	HRESULT			hr				= E_FAIL;
	CCol			col;
	DBCOLUMNDESC	*rgColumnDesc	= NULL;
	DBORDINAL		cColumnDesc		= 0;
	BOOL			fExists;
	DBID			*pTableID		= NULL;
	IUnknown		*pRowset		= NULL;		// [out] pointer to outer interface
	CTable			*pTable = new CTable(m_pThisTestModule->m_pIUnknown2, (LPWSTR)gwszModuleName);

	TESTC(nProperties);
	DuplicateColumnDesc(m_rgColumnDesc, m_cColumnDesc, &rgColumnDesc);
	cColumnDesc = m_cColumnDesc;
	ReleaseAllColumnPropSets(rgColumnDesc, cColumnDesc);

	for (n=0; n<nProperties; n++)
	{
		SetProperty(&rgPropertySets, &cPropertySets, rgPropID[n],
					rgDBType[n], rgValue[n], rgOptions[n], DB_NULLID, DBPROPSET_ROWSET);
	}


	hr = CreateAndCheckTable(m_pITableDefinition, NULL, NULL, cColumnDesc, rgColumnDesc, *pRIID,
		cPropertySets, rgPropertySets, &pTableID, &pRowset);

	SAFE_RELEASE(pRowset);

	if (	pTableID
		&&	DB_E_NOTABLE != hr
		&&	DB_E_DUPLICATETABLEID != hr
		&&	CHECK(pTable->DoesTableExist(pTableID, &fExists), S_OK)
		&&	fExists)
		CHECK(m_pITableDefinition->DropTable(pTableID), S_OK);
	
	delete pTable;
	ReleaseDBID(pTableID);

	if (FAILED(hr))
	{
		odtLog << "Could not create a table with a specified property set.\n";
		if (	(1 == nProperties) 
			&& 	(DBPROPSTATUS_OK != rgPropertySets[0].rgProperties[0].dwStatus)
			&&		(	(DBPROPOPTIONS_REQUIRED == rgPropertySets[0].rgProperties[0].dwStatus) 
					&&	!CHECK(hr, DB_E_ERRORSOCCURRED)))
		{
			odtLog << "wrong value for dwStatus in rowset property";
			goto CLEANUP;
		}
	}
	else
		// check the creation of the rowset
		if (	(1 == nProperties) 
			&&	(	(	(DBPROPSTATUS_OK == rgPropertySets[0].rgProperties[0].dwStatus) 
					&&	!CHECK(hr, S_OK))
				||	(	(DBPROPSTATUS_OK != rgPropertySets[0].rgProperties[0].dwStatus) 
					&&	!CHECK(hr, DB_S_ERRORSOCCURRED))))
		{
			odtLog << "wrong value for dwStatus in rowset property";
			goto CLEANUP;
		}

	fRes = TRUE;

CLEANUP:
	FreeProperties( &cPropertySets, &rgPropertySets);
	ReleaseColumnDesc(rgColumnDesc, cColumnDesc);
	return fRes;
} //TCITableDefinition::CreateWithRowsetProps




//--------------------------------------------------------------------------
//
// creates a table with not nullable column
//--------------------------------------------------------------------------
HRESULT TCITableDefinition::CreateTableWithNoNullableColumns(	
	CTable		*pTable,						// @param [IN] pointer to CTable 
	DBCOUNTITEM ulRowCount,						// @parm [IN] # of Rows to insert into table, 1 based
	DBORDINAL	ulIndex /*=0*/,					// @parm [IN] Column Number of index, 1 based (Default=1)
	WCHAR		*pwszTableName/*=NULL*/,		// @parm [IN] TableName, if NULL call MakeTableName() (Default=NULL)
	EVALUE		eValue/*=PRIMARY*/,				// @parm [IN] Insert PRIMARY or SECONDARY data (Default=PRIMARY)
	BOOL		fFirstUpdateable/*=FALSE*/		// @parm [IN] TRUE means first column will be autoinc (Default=FALSE)
)
{
	HRESULT				hr = E_FAIL;
	// customize the table so that no nullable columns is added
	DBCOLUMNDESC		*rgNewColumnDesc = NULL;
	DBORDINAL			indexCol;
	
	// create a new table with a NULLABLE column
	DuplicateColumnDesc(m_rgColumnDesc, m_cColumnDesc, &rgNewColumnDesc);

	for (indexCol = 0; indexCol < m_cColumnDesc; indexCol++)
	{
		SetProperty(&rgNewColumnDesc[indexCol].rgPropertySets, &rgNewColumnDesc[indexCol].cPropertySets,
				DBPROP_COL_NULLABLE, 
				VT_BOOL, (LPVOID)VARIANT_FALSE, 
				DBPROPOPTIONS_REQUIRED);
	}

	// by setting DBCOLUMNDESC, all nullable type column are created as nullable 
	pTable->SetColumnDesc(rgNewColumnDesc, m_cColumnDesc);
	pTable->SetBuildColumnDesc(FALSE);
	
	TESTC_(pTable->CreateTable(ulRowCount, ulIndex, pwszTableName, eValue, fFirstUpdateable), S_OK);
	
	pTable->AddInfoFromColumnsSchemaRowset(m_pITableDefinition, pTable->GetTableName());
	
	hr = S_OK;

CLEANUP:
	return hr;
} //TCITableDefinition::CreateTableWithNoNullableColumns



HRESULT TCITableDefinition::AddUniqueConstraint(
	CTable				*pTable, 
	DBORDINAL			ulCol,
	DBDEFERRABILITY		Deferrability		/*= 0*/
)
{
	return AddKeyConstraint(DBCONSTRAINTTYPE_UNIQUE, pTable, 1, &ulCol, Deferrability);
} //TCITableDefinition::AddUniqueConstraint



HRESULT TCITableDefinition::AddUniqueConstraint(
	CTable				*pTable, 
	DBORDINAL			cCol,
	DBORDINAL			*rgCol,
	DBDEFERRABILITY		Deferrability		/*= 0*/
)
{
	return AddKeyConstraint(DBCONSTRAINTTYPE_UNIQUE, pTable, cCol, rgCol, Deferrability);
} //TCITableDefinition::AddUniqueConstraint



HRESULT TCITableDefinition::AddPrimaryKeyConstraint(
	CTable				*pTable, 
	DBORDINAL			ulCol,
	DBDEFERRABILITY		Deferrability		/*= 0*/
)
{
	return AddKeyConstraint(DBCONSTRAINTTYPE_PRIMARYKEY, pTable, 1, &ulCol, Deferrability);
} //TCITableDefinition::AddPrimaryKeyConstraint



HRESULT TCITableDefinition::AddPrimaryKeyConstraint(
	CTable				*pTable, 
	DBORDINAL			cCol,
	DBORDINAL			*rgCol,
	DBDEFERRABILITY		Deferrability		/*= 0*/
)
{
	return AddKeyConstraint(DBCONSTRAINTTYPE_PRIMARYKEY, pTable, cCol, rgCol, Deferrability);
} //TCITableDefinition::AddPrimaryKeyConstraint



HRESULT TCITableDefinition::AddKeyConstraint(
	DBCONSTRAINTTYPE	ConstraintType,
	CTable				*pTable, 
	DBORDINAL			cCol,
	DBORDINAL			*rgCol,
	DBDEFERRABILITY		Deferrability		/*= 0*/
)
{
	HRESULT			hr = E_FAIL;
	CCol			col;
	CKeyConstraint	cons(ConstraintType);
	DBORDINAL		ulRow;

	TESTC(NULL != m_pITDWC);
	TESTC(NULL != pTable);
	TESTC(0 == cCol || NULL != rgCol);
	TESTC(DBCONSTRAINTTYPE_UNIQUE == ConstraintType || DBCONSTRAINTTYPE_PRIMARYKEY == ConstraintType);
	
	TESTC_(cons.SetConstraint(pTable, cCol, rgCol, Deferrability), S_OK);

	TESTC_(pTable->GetColInfo(rgCol[0], col), S_OK);

	hr = AddConstraintAndCheck(m_pITDWC, &pTable->GetTableID(), cons);

	// check that inserting a row with duplicate key is not accepted
	if (SUCCEEDED(hr))
	{
		ulRow = pTable->GetNextRowNumber();
		// check that you can not add a row to the base table (no nulls are inserted, right?)
		if (S_OK == pTable->Insert(ulRow))
			CHECK(pTable->Insert(ulRow), DB_E_INTEGRITYVIOLATION);
	}

CLEANUP:
	return hr;
} // TCITableDefinition::AddKeyConstraint



HRESULT TCITableDefinition::AddForeignKeyConstraint(
	CTable				*pBaseTable, 
	DBORDINAL			cBaseCol,
	DBORDINAL			*rgBaseCol,
	CTable				*pReferencedTable, 
	DBORDINAL			cReferencedCol,
	DBORDINAL			*rgReferencedCol,
	DBMATCHTYPE			MatchType			/*= DBMATCHTYPE_FULL*/,
	DBUPDELRULE			UpdateRule			/*= DBUPDELRULE_NOACTION*/,
	DBUPDELRULE			DeleteRule			/*= DBUPDELRULE_NOACTION*/,
	DBDEFERRABILITY		Deferrability		/*= 0*/
)
{
	HRESULT			hr		= E_FAIL;
	CForeignKeyCons	cons;
	DBORDINAL		ulRow;
	DBORDINAL		index;
	DBORDINAL		ulMaxCol;

	TESTC_(cons.SetConstraint(pBaseTable, cBaseCol, rgBaseCol,
		pReferencedTable, cReferencedCol, rgReferencedCol,
		MatchType, UpdateRule, DeleteRule, Deferrability), S_OK);

	hr = AddConstraintAndCheck(m_pITDWC, &pBaseTable->GetTableID(), cons);

	if (S_OK == hr)
	{
		// find the maximum column of the foreign key
		for (index = 1, ulMaxCol = rgBaseCol[0]; index < cBaseCol; index++)
		{
			ulMaxCol = (ulMaxCol < rgBaseCol[index])? rgBaseCol[index]: ulMaxCol;
		}

		ulRow = pReferencedTable->GetNextRowNumber();
		ulRow = (ulRow <= ulMaxCol)? ulMaxCol + 1: ulRow;
		// check that you can not add a row to the base table (no nulls are inserted, right?)
		// Note: if there is a NULL column in the foreign key schema this insert 
		// rightfully succeeds 
		TEST2C_(pBaseTable->Insert(ulRow), DB_E_INTEGRITYVIOLATION, E_FAIL);
		// check that you can add a row to the referenced table
		CHECK(pReferencedTable->Insert(ulRow), S_OK);
		// check that you can now add a row to the base table
		CHECK(pBaseTable->Insert(ulRow), S_OK);
	}

CLEANUP:
	return hr;
} // TCITableDefinition::AddForeignKeyConstraint




//--------------------------------------------------------------------------
//
// @cmember Termination function
//--------------------------------------------------------------------------
BOOL TCITableDefinition::Terminate()
{
	DeleteCriticalSection(&m_CriticalSection);
	ULONG	nTables;
	nTables = GetNoOfTables();
	ReleaseColumnDesc(m_rgColumnDesc, m_cColumnDesc);
	if (nTables>m_nTables)
		odtLog << "Numer of residual tables: " << nTables-m_nTables << "\n";
	nResidualTables += nTables-m_nTables;
	SAFE_RELEASE(m_pITableDefinition);
	SAFE_RELEASE(m_pITDWC);
	ReleaseDBSession();
	ReleaseDataSourceObject();
	m_ColList.RemoveAll();
	PROVIDER_FREE(m_pwszInvalidTableChars);
	PROVIDER_FREE(m_pwszInvalidColChars);
	return(CSessionObject::Terminate());
} //TCITableDefinition::Terminate




// {{ TCW_TC_PROTOTYPE(TCAddColumn)
//*-----------------------------------------------------------------------
//| Test Case:		TCAddColumn - Testcase for ITableDefinition::AddColumn
//|	Created:			09/10/97
//*-----------------------------------------------------------------------

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



// {{ TCW_VAR_PROTOTYPE(1)
//*-----------------------------------------------------------------------
// @mfunc Table doesn't exist => DB_E_NOTABLE
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCAddColumn::Variation_1()
{
	BOOL			fTestRes = TEST_PASS, fExists;
	DBID			TableID;
	DBID			*pColumnID = NULL;
	DBCOLUMNDESC	*rgColumnDesc	= NULL;
	ULONG			cColumnDesc		= 1;

	DuplicateColumnDesc(m_rgColumnDesc, cColumnDesc, &rgColumnDesc);
	ReleaseAllColumnPropSets(rgColumnDesc, cColumnDesc);
	TableID.eKind = DBKIND_NAME;
	// CTable::MakeTableName() generates a name that doesn't exist in the catalog
	m_pTable->MakeTableName(NULL);
	TableID.uName.pwszName	= m_pTable->GetTableName();

	// try to add a column on this table that doesn't exist
	if (!CHECK(m_hr = m_pITableDefinition->AddColumn(&TableID, rgColumnDesc, &pColumnID), DB_E_NOTABLE))
		fTestRes = TEST_FAIL;

	if (!CHECK(m_pTable->DoesTableExist(&TableID, &fExists), S_OK) || fExists)
	{
		odtLog << "Table " << TableID.uName.pwszName << " was added by AddColumn!\n";
		fTestRes = TEST_FAIL;
	}

	ReleaseColumnDesc(rgColumnDesc, cColumnDesc);
	return fTestRes;
}
// }}


// {{ TCW_VAR_PROTOTYPE(2)
//*-----------------------------------------------------------------------
// @mfunc The table is in use => DB_E_TABLEINUSE
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCAddColumn::Variation_2()
{
	TBEGIN
	DBID				*pColumnID			= NULL;
	IRowset				*pIRowset			= NULL;
	IRowsetChange		*pIRowsetChange		= NULL;
	IRowsetChange		*pIRowsetChange2	= NULL;
	HRESULT				hr;
	HACCESSOR			hAccessor			= NULL;
	BYTE				*pData				= NULL;
	DBCOUNTITEM			cBindings			= 0;
	DBBINDING			*rgBindings			= NULL;
	const DBORDINAL		cColsToBind			= 1;
	LONG_PTR			rgColsToBind[cColsToBind];
	HROW				*rghRow				= NULL;
	DBCOUNTITEM			cRowsObtained		= 0;
	DBPROPSET			rgPropSets[1];
	DBPROP				rgProperties[1];
	DBLENGTH			ulRowSize;
	DBCOUNTITEM			nRowNo;
	DBCOUNTITEM			nRowsInTable		= 0;
	DBCOLUMNDESC		*rgColumnDesc		= NULL;
	DBORDINAL			cColumnDesc			= 0;
	const DBCOUNTITEM	nRowsToInsert		= 10;

	DuplicateColumnDesc(m_rgColumnDesc, m_cColumnDesc, &rgColumnDesc);
	cColumnDesc = m_cColumnDesc;
	ReleaseAllColumnPropSets(rgColumnDesc, cColumnDesc);
	m_pTable->SetColumnDesc(rgColumnDesc, cColumnDesc-1);
	m_pTable->SetBuildColumnDesc(FALSE);
	// ask for a IRowsetChange interface
	m_pTable->SetRowset((IUnknown**)&pIRowsetChange);
	if (SettableProperty(DBPROP_IRowsetChange, DBPROPSET_ROWSET))
		m_pTable->SetRIID((struct _GUID*)&IID_IRowsetChange);
	else
		m_pTable->SetRIID((struct _GUID*)&IID_IRowset);

	// Set properties
	FILL_PROP_SET(rgPropSets[0], 1, rgProperties, DBPROPSET_ROWSET);
	FILL_PROP(rgProperties[0], DBPROP_OWNINSERT, VT_BOOL, V_BOOL, VARIANT_TRUE, DBPROPOPTIONS_REQUIRED);
	m_pTable->SetPropertySets(rgPropSets, NUMELEM(rgPropSets));

	// creates the table and populates it, using the returned pIRowsetChange
	TESTC_(hr = m_pTable->CreateTable(0, 0), S_OK);
	
	// check whether iRowsetChange is available
	VerifyInterface(pIRowsetChange, IID_IRowsetChange, ROWSET_INTERFACE, (IUnknown**)&pIRowsetChange2);
	if (pIRowsetChange2)
	{
		for (nRowNo = 0; nRowNo < nRowsToInsert; nRowNo++)
		{
			if (S_OK == Insert(0, (IUnknown*)pIRowsetChange))
				nRowsInTable++;
		}
	}

	TESTC(VerifyInterface(pIRowsetChange, IID_IRowset, ROWSET_INTERFACE, (IUnknown**)&pIRowset));
	
	// get a row
	if (0 < nRowsInTable)
	{
		m_hr = pIRowset->GetNextRows(0, 0,					// hChapter & lRowsOffset
										1,					// number of rows to be retrieved
										&cRowsObtained,		//number of rows actually get
										&rghRow				// array of handlers to rows
										);
		if (!CHECK(m_hr, S_OK))
		{
			odtLog << "insuccess on initial IRowset::GetNextRows\n";
			m_hr = pIRowset->ReleaseRows(cRowsObtained, rghRow, NULL, NULL, NULL);
		}
		// test the return value of IRowset::RestartPosition
		CHECK(m_hr = pIRowset->ReleaseRows(cRowsObtained, rghRow, NULL, NULL, NULL), S_OK);
		PROVIDER_FREE(rghRow);
		cRowsObtained = 0;		
	}
	else
		odtLog << "Could not insert any row in the table\n";

	
	// check if a column can be added, on the table in use (look for S_OK or DB_E_TABLEINUSE)
	hr = AddColumnAndCheck(&m_pTable->GetTableID(), &rgColumnDesc[cColumnDesc-1], 
		&pColumnID);
	
	if (hr == S_OK)
	{
		odtLog << "Column was added while a rowset was still open on table.\n";

		if (1 > nRowsInTable)
			goto CLEANUP;

		// see how it reacts to RestartPosition and if the new column can be read
		hr = pIRowset->RestartPosition(0); // a non-chaptered rowset
		if (hr == DB_S_COLUMNSCHANGED)
		{
			odtLog << "DB_S_COLUMNSCHANGED returned on pIRowset->RestartPosition\n";

			// get the value of the new column in the first row
			//Get an accessor with all the writeable columns
			rgColsToBind[0] = (LONG_PTR)cColumnDesc-1;
			if (!CHECK(hr = GetAccessorAndBindings(
					pIRowset,									// pIUnknRowsetObject
					DBACCESSOR_ROWDATA,							// accessor flags
					&hAccessor, &rgBindings, &cBindings,		// accessor handler, array and number of bindings created
					&ulRowSize,									// [OUT] row size
					DBPART_VALUE |DBPART_STATUS |DBPART_LENGTH,	// types of bindings to do
					USE_COLS_TO_BIND_ARRAY,						// eColsByRef specifies that cols to be bind 
																// are given as an array
					FORWARD,									// eBindingOrder
					NO_COLS_BY_REF,								// eColsByRef
					NULL, NULL,
					NULL, DBTYPE_EMPTY, 						// ppStringsBufferOut & dwModifier
					1, rgColsToBind								// size and array of cols to be bind
					), S_OK))
			{
				odtLog << "problems getting accessor and bindings\n";
			}

			// alloc memory for the row data
			SAFE_ALLOC(pData, BYTE, ulRowSize);

			// get the rowset window 
			m_hr = pIRowset->GetNextRows(0, 0,					// hChapter & lRowsOffset
											1,					// number of rows to be retrieved
											&cRowsObtained,		//number of rows actually get
											&rghRow				// array of handlers to rows
										);
			if (S_OK != m_hr || !COMPARE(1 == cRowsObtained, TRUE))
			{
				odtLog << "after RestartPosition, could not get the rows\n";
				CHECK(m_hr = pIRowset->ReleaseRows(cRowsObtained, rghRow, NULL, NULL, NULL), S_OK);
				goto CLEANUP;
			}

			// read data
			CHECK(m_hr = pIRowset->GetData(rghRow[0], hAccessor, pData), S_OK);
			if ((S_OK != m_hr) || 
				((DBSTATUS_S_OK != ((DATA*)pData)->sStatus) &&
				 !COMPARE(DBSTATUS_S_ISNULL == ((DATA*)pData)->sStatus, TRUE) ))
			{
				odtLog << "can't get the data from the newly created column\n";
			}
			else
				odtLog << "data read!\n";
			CHECK(m_hr = pIRowset->ReleaseRows(cRowsObtained, rghRow, NULL, NULL, NULL), S_OK);
		}
	}
	else
	{
		odtLog << "DB_E_TABLEINUSE was returned when a column was to be added on a table whith an open rowset.\n";
		CHECK(hr, DB_E_TABLEINUSE);
	}

CLEANUP:
	m_pTable->SetRowset(NULL);
	SAFE_RELEASE(pIRowsetChange2);
	SAFE_RELEASE(pIRowset);
	SAFE_FREE(pData);
	m_pTable->SetNoOfColumnDesc(cColumnDesc);
	m_pTable->SetNoOfPropertySets(0);
	m_pTable->SetPropertySets(NULL);
	CHECK(m_pTable->DropTable(), S_OK);
	ReleaseDBID(pColumnID);
	FreeAccessorBindings(cBindings, rgBindings);
	SAFE_FREE(pData);
	SAFE_FREE(rghRow);
	TRETURN
}
// }}


// {{ TCW_VAR_PROTOTYPE(3)
//*-----------------------------------------------------------------------
// @mfunc *pTableID = DB_NULLID => DB_E_NOTABLE
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCAddColumn::Variation_3()
{
	BOOL			fTestRes		= TEST_PASS;
	DBID			*pColumnID		= NULL;
	DBCOLUMNDESC	*rgColumnDesc	= NULL;
	ULONG			cColumnDesc		= 1;

	DuplicateColumnDesc(m_rgColumnDesc, cColumnDesc, &rgColumnDesc);
	ReleaseAllColumnPropSets(rgColumnDesc, cColumnDesc);

	// try to add a column from this table that doesn't exist
	if (!CHECK(m_pITableDefinition->AddColumn((DBID*)&DB_NULLID, rgColumnDesc, &pColumnID), DB_E_NOTABLE))
		fTestRes = TEST_FAIL;

	ReleaseDBID(pColumnID);
	ReleaseColumnDesc(rgColumnDesc, cColumnDesc);
	return fTestRes;
}
// }}


// {{ TCW_VAR_PROTOTYPE(4)
//*-----------------------------------------------------------------------
// @mfunc pTableID = NULL => E_INVALIDARG
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCAddColumn::Variation_4()
{
	BOOL			fTestRes = TEST_PASS;
	DBID			*pColumnID = NULL;
	DBCOLUMNDESC	*rgColumnDesc	= NULL;
	ULONG			cColumnDesc		= 1;

	DuplicateColumnDesc(m_rgColumnDesc, cColumnDesc, &rgColumnDesc);
	ReleaseAllColumnPropSets(rgColumnDesc, cColumnDesc);

	// try to add a column from this table that doesn't exist
	if (!CHECK(m_hr = m_pITableDefinition->AddColumn(NULL, rgColumnDesc, &pColumnID), E_INVALIDARG))
		fTestRes = TEST_FAIL;

	ReleaseDBID(pColumnID);
	ReleaseColumnDesc(rgColumnDesc, cColumnDesc);
	return fTestRes;
}
// }}


// {{ TCW_VAR_PROTOTYPE(5)
//*-----------------------------------------------------------------------
// @mfunc Maximum length for table name => S_OK
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCAddColumn::Variation_5()
{
	TBEGIN
	DBID			TableID;
	DBID			*pColumnID		= NULL;
	DBCOLUMNDESC	*rgColumnDesc	= NULL;
	DBORDINAL		cColumnDesc		= 0;

	DuplicateColumnDesc(m_rgColumnDesc, m_cColumnDesc, &rgColumnDesc);
	cColumnDesc = m_cColumnDesc;
	ReleaseAllColumnPropSets(rgColumnDesc, cColumnDesc);
	m_pTable->MakeTableName(NULL);
	TableID.eKind			= DBKIND_NAME;
	TableID.uName.pwszName	= BuildValidName(m_cMaxTableName, m_pTable->GetTableName());
	m_pTable->SetColumnDesc(rgColumnDesc, cColumnDesc-1);
	m_pTable->SetBuildColumnDesc(FALSE);
	PRVTRACE(L"***TCADDColumn::Variation_5(): TableName=%s, len=%d\n", 
		TableID.uName.pwszName, wcslen(TableID.uName.pwszName));

	TESTC_(m_pTable->CreateTable(0, 0, TableID.uName.pwszName), S_OK);

	// try to add a column to this maximum length name table
	// prepare the column to be added
	TESTC_(AddColumnAndCheck(&m_pTable->GetTableID(), &rgColumnDesc[cColumnDesc-1], &pColumnID), S_OK);

CLEANUP:
	CHECK(m_pTable->DropTable(), S_OK);
	m_pTable->SetNoOfColumnDesc(cColumnDesc);
	ReleaseDBID(&TableID, FALSE);	// don't want to release the pointer, just the container
	ReleaseDBID(pColumnID);
	TRETURN
}
// }}


// {{ TCW_VAR_PROTOTYPE(6)
//*-----------------------------------------------------------------------
// @mfunc the table name is 1 char too long => DB_E_NOTABLE
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCAddColumn::Variation_6()
{
	TBEGIN
	DBID			TableID;
	DBID			*pColumnID = NULL;
	WCHAR			*pwszTableName;
	DBCOLUMNDESC	*rgColumnDesc	= NULL;
	DBORDINAL		cColumnDesc		= 0;

	DuplicateColumnDesc(m_rgColumnDesc, m_cColumnDesc, &rgColumnDesc);
	cColumnDesc = m_cColumnDesc;
	ReleaseAllColumnPropSets(rgColumnDesc, cColumnDesc);
	m_pTable->MakeTableName(NULL);
	TableID.eKind			= DBKIND_NAME;
	GetLiteralInfo();
	TableID.uName.pwszName	= BuildValidName(m_cMaxTableName, m_pTable->GetTableName());
	pwszTableName			= BuildValidName(m_cMaxTableName+1, m_pTable->GetTableName());
	// prepare arguments for table creation
	m_pTable->SetColumnDesc(rgColumnDesc, cColumnDesc-1);
	m_pTable->SetBuildColumnDesc(FALSE);
	PRVTRACE(L"***TCADDColumn::Variation_6(): TableName=%s, len=%d\n", TableID.uName.pwszName, 
		wcslen(TableID.uName.pwszName));

	TESTC_(m_pTable->CreateTable(0, 0, TableID.uName.pwszName), S_OK);
	
	// try to add a column, spec the table name plus a char as a table name
	PROVIDER_FREE(TableID.uName.pwszName);
	TableID.uName.pwszName = pwszTableName;
	TESTC_(AddColumnAndCheck(&TableID, &rgColumnDesc[cColumnDesc-1], &pColumnID), DB_E_NOTABLE);

CLEANUP:
	CHECK(m_pTable->DropTable(), S_OK);
	m_pTable->SetNoOfColumnDesc(cColumnDesc);
	ReleaseDBID(pColumnID);
	ReleaseDBID(&TableID, FALSE);
	TRETURN
}
// }}


// {{ TCW_VAR_PROTOTYPE(7)
//*-----------------------------------------------------------------------
// @mfunc invalid table name => DB_E_NOTABLE
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCAddColumn::Variation_7()
{
	BOOL			fTestRes = TEST_PASS;
	DBID			TableID;
	DBID			*pColumnID = NULL;
	size_t			m, n;
	DBCOLUMNDESC	*rgColumnDesc	= NULL;
	ULONG			cColumnDesc		= 1;

	DuplicateColumnDesc(m_rgColumnDesc, cColumnDesc, &rgColumnDesc);
	ReleaseAllColumnPropSets(rgColumnDesc, cColumnDesc);
	m_pTable->MakeTableName(NULL);
	TableID.eKind			= DBKIND_NAME;
	m = min(m_cMaxTableName, n=5+wcslen(m_pTable->GetTableName()));
	TableID.uName.pwszName	= BuildInvalidName(m, m_pTable->GetTableName(), m_pwszInvalidTableChars);
	PRVTRACE(L"***TCADDColumn::Variation_7(): TableName=%s, len=%d\n", TableID.uName.pwszName, 
		wcslen(TableID.uName.pwszName));

	if (!CHECK(m_hr = m_pITableDefinition->AddColumn(&TableID, &rgColumnDesc[0], &pColumnID), DB_E_NOTABLE))
			fTestRes = TEST_FAIL;

	ReleaseDBID(pColumnID);
	ReleaseDBID(&TableID, FALSE);
	ReleaseColumnDesc(rgColumnDesc, cColumnDesc);
	return fTestRes;
}
// }}


// {{ TCW_VAR_PROTOTYPE(8)
//*-----------------------------------------------------------------------
// @mfunc pColumnDesc->dbcid = DB_NULLID
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCAddColumn::Variation_8()
{
	TBEGIN
	DBID			*pColumnID = NULL;
	DBCOLUMNDESC	*rgColumnDesc	= NULL;
	DBORDINAL		cColumnDesc		= 0;

	DuplicateColumnDesc(m_rgColumnDesc, m_cColumnDesc, &rgColumnDesc);
	cColumnDesc = m_cColumnDesc;
	ReleaseAllColumnPropSets(rgColumnDesc, cColumnDesc);
	m_pTable->SetColumnDesc(rgColumnDesc, cColumnDesc-1);
	m_pTable->SetBuildColumnDesc(FALSE);

	TESTC_(m_pTable->CreateTable(0, 0), S_OK);

	// try to add a column with a DB_NULLID colid to this table
	if (rgColumnDesc[cColumnDesc-1].dbcid.uName.pwszName)
		PROVIDER_FREE(rgColumnDesc[cColumnDesc-1].dbcid.uName.pwszName);
	memcpy(&rgColumnDesc[cColumnDesc-1].dbcid, (DBID*)&DB_NULLID, sizeof(DBID));
	TESTC_(AddColumnAndCheck(&m_pTable->GetTableID(), &rgColumnDesc[cColumnDesc-1], 
		&pColumnID), DB_E_BADCOLUMNID);

CLEANUP:
	CHECK(m_pTable->DropTable(), S_OK);
	m_pTable->SetNoOfColumnDesc(cColumnDesc);
	ReleaseDBID(pColumnID);
	TRETURN
}
// }}


// {{ TCW_VAR_PROTOTYPE(9)
//*-----------------------------------------------------------------------
// @mfunc Column name pointer is NULL => DB_E_BADCOLUMNID
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCAddColumn::Variation_9()
{
	TBEGIN
	DBID			*pColumnID		= NULL;
	DBCOLUMNDESC	*rgColumnDesc	= NULL;
	DBORDINAL		cColumnDesc		= 0;

	DuplicateColumnDesc(m_rgColumnDesc, m_cColumnDesc, &rgColumnDesc);
	cColumnDesc = m_cColumnDesc;
	ReleaseAllColumnPropSets(rgColumnDesc, cColumnDesc);
	m_pTable->SetBuildColumnDesc(FALSE);
	m_pTable->SetColumnDesc(rgColumnDesc, cColumnDesc-1);

	TESTC_(m_pTable->CreateTable(0, 0), S_OK); 

	// try to add a column with a NULL value for name pointer
	if (rgColumnDesc[cColumnDesc-1].dbcid.uName.pwszName)
		PROVIDER_FREE(rgColumnDesc[cColumnDesc-1].dbcid.uName.pwszName);
	rgColumnDesc[cColumnDesc-1].dbcid.eKind = DBKIND_NAME;
	rgColumnDesc[cColumnDesc-1].dbcid.uName.pwszName = NULL;
	
	TESTC_(AddColumnAndCheck(&m_pTable->GetTableID(), 
			&rgColumnDesc[cColumnDesc-1], &pColumnID), DB_E_BADCOLUMNID);

CLEANUP:
	CHECK(m_pTable->DropTable(), S_OK);
	m_pTable->SetNoOfColumnDesc(cColumnDesc);
	ReleaseDBID(pColumnID);
	TRETURN
}
// }}


// {{ TCW_VAR_PROTOTYPE(10)
//*-----------------------------------------------------------------------
// @mfunc column name is an empty string => DB_E_BADCOLUMNID
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCAddColumn::Variation_10()
{
	TBEGIN
	DBID			*pColumnID		= NULL;
	DBCOLUMNDESC	*rgColumnDesc	= NULL;
	DBORDINAL		cColumnDesc		= 0;

	DuplicateColumnDesc(m_rgColumnDesc, m_cColumnDesc, &rgColumnDesc);
	cColumnDesc = m_cColumnDesc;
	ReleaseAllColumnPropSets(rgColumnDesc, cColumnDesc);
	m_pTable->SetColumnDesc(rgColumnDesc, cColumnDesc-1);
	m_pTable->SetBuildColumnDesc(FALSE);

	// create a table with cColumnDesc-1 columns
	TESTC_(m_pTable->CreateTable(0, 0), S_OK);

	// try to add a column with a NULL value for name pointer
	if (rgColumnDesc[cColumnDesc-1].dbcid.uName.pwszName)
		PROVIDER_FREE(rgColumnDesc[cColumnDesc-1].dbcid.uName.pwszName);
	rgColumnDesc[cColumnDesc-1].dbcid.eKind = DBKIND_NAME;
	rgColumnDesc[cColumnDesc-1].dbcid.uName.pwszName = wcsDuplicate(L"");
	
	TESTC_(AddColumnAndCheck(&m_pTable->GetTableID(), 
				&rgColumnDesc[cColumnDesc-1], &pColumnID), DB_E_BADCOLUMNID);

CLEANUP:
	CHECK(m_pTable->DropTable(), S_OK);
	m_pTable->SetNoOfColumnDesc(cColumnDesc);
	ReleaseDBID(pColumnID);
	TRETURN
}
// }}


// {{ TCW_VAR_PROTOTYPE(11)
//*-----------------------------------------------------------------------
// @mfunc Maximum length of column name => S_OK
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCAddColumn::Variation_11()
{
	TBEGIN
	DBID			*pColumnID		= NULL;
	WCHAR			*pwszName		= NULL;
	DBCOLUMNDESC	*rgColumnDesc	= NULL;
	DBORDINAL		cColumnDesc		= 0;

	DuplicateColumnDesc(m_rgColumnDesc, m_cColumnDesc, &rgColumnDesc);
	cColumnDesc = m_cColumnDesc;
	ReleaseAllColumnPropSets(rgColumnDesc, cColumnDesc);
	m_pTable->SetColumnDesc(rgColumnDesc, cColumnDesc-1);
	m_pTable->SetBuildColumnDesc(FALSE);
	m_pTable->MakeTableName(NULL);
	pwszName = wcsDuplicate(m_pTable->GetTableName());

	TESTC_(m_pTable->CreateTable(0, 0), S_OK);

	// try to add a column with a maximum size for column name 
	if (rgColumnDesc[cColumnDesc-1].dbcid.uName.pwszName)
		PROVIDER_FREE(rgColumnDesc[cColumnDesc-1].dbcid.uName.pwszName);
	rgColumnDesc[cColumnDesc-1].dbcid.eKind = DBKIND_NAME;
	rgColumnDesc[cColumnDesc-1].dbcid.uName.pwszName = BuildValidName(m_cMaxColName, pwszName);
	odtLog << "A maximum length column name: " << rgColumnDesc[cColumnDesc-1].dbcid.uName.pwszName << 
		", length=" << wcslen(rgColumnDesc[cColumnDesc-1].dbcid.uName.pwszName) << "\n";
	
	TESTC_(AddColumnAndCheck(&m_pTable->GetTableID(), &rgColumnDesc[cColumnDesc-1], 
		&pColumnID), S_OK);

CLEANUP:
	CHECK(m_pTable->DropTable(), S_OK);
	m_pTable->SetNoOfColumnDesc(cColumnDesc);
	ReleaseDBID(pColumnID);
	PROVIDER_FREE(pwszName);
	TRETURN
}
// }}


// {{ TCW_VAR_PROTOTYPE(12)
//*-----------------------------------------------------------------------
// @mfunc 1-char-too-long column name => DB_E_BADCOLUMNID
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCAddColumn::Variation_12()
{
	TBEGIN
	WCHAR			*pwszName		= NULL;
	DBID			*pColumnID		= NULL;
	DBCOLUMNDESC	*rgColumnDesc	= NULL;
	DBORDINAL		cColumnDesc		= 0;

	DuplicateColumnDesc(m_rgColumnDesc, m_cColumnDesc, &rgColumnDesc);
	cColumnDesc = m_cColumnDesc;
	ReleaseAllColumnPropSets(rgColumnDesc, cColumnDesc);
	m_pTable->SetColumnDesc(rgColumnDesc, cColumnDesc-1);
	m_pTable->SetBuildColumnDesc(FALSE);
	m_pTable->MakeTableName(NULL);
	pwszName = wcsDuplicate(m_pTable->GetTableName());

	TESTC_(m_pTable->CreateTable(0, 0), S_OK);

	// try to add a column with a name too long
	if (rgColumnDesc[cColumnDesc-1].dbcid.uName.pwszName)
		PROVIDER_FREE(rgColumnDesc[cColumnDesc-1].dbcid.uName.pwszName);
	rgColumnDesc[cColumnDesc-1].dbcid.eKind = DBKIND_NAME;
	rgColumnDesc[cColumnDesc-1].dbcid.uName.pwszName = BuildValidName(m_cMaxColName+1, pwszName);
	odtLog << "A 1 char too long column name: " << rgColumnDesc[cColumnDesc-1].dbcid.uName.pwszName << 
		", length=" << wcslen(rgColumnDesc[cColumnDesc-1].dbcid.uName.pwszName) << "\n";
	
	TESTC_(AddColumnAndCheck(&m_pTable->GetTableID(), 
		&rgColumnDesc[cColumnDesc-1], &pColumnID), DB_E_BADCOLUMNID);

CLEANUP:
	CHECK(m_pTable->DropTable(), S_OK);
	SAFE_FREE(pwszName);
	m_pTable->SetNoOfColumnDesc(cColumnDesc);
	ReleaseDBID(pColumnID);
	TRETURN
}
// }}


// {{ TCW_VAR_PROTOTYPE(13)
//*-----------------------------------------------------------------------
// @mfunc Add a column for each provider type, maximum column size => S_OK
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCAddColumn::Variation_13()
{
	TBEGIN
	DBID			*pColumnID = NULL;
	DBORDINAL		i;
	DBCOLUMNDESC	*pColumnDesc = NULL;
	DBCOLUMNDESC	*rgColumnDesc	= NULL;
	DBORDINAL		cColumnDesc		= 0;

	DuplicateColumnDesc(m_rgColumnDesc, m_cColumnDesc, &rgColumnDesc);
	cColumnDesc = m_cColumnDesc;
	ReleaseAllColumnPropSets(rgColumnDesc, cColumnDesc);
	DuplicateColumnDesc(rgColumnDesc, 1, &pColumnDesc);
	PROVIDER_FREE(pColumnDesc->dbcid.uName.pwszName);
	pColumnDesc->dbcid.uName.pwszName = wcsDuplicate(L"FirstColumn");
	// for each type in DBCOLUMNDESC, add a column with maximum column size
	SetMaximumColSize(rgColumnDesc, cColumnDesc);
	m_pTable->SetBuildColumnDesc(FALSE);
	m_pTable->SetColumnDesc(pColumnDesc, 1);
	for (i=0; i<cColumnDesc; i++)
	{
		// create a table with a single column, equal to the first one in the row
		CHECK(m_hr = m_pTable->CreateTable(0, 0), S_OK);

		if (FAILED(m_hr))
			continue;

		// try to add a column from rgColumnDesc[i]
		odtLog <<	"column name:" << rgColumnDesc[i].dbcid.uName.pwszName << 
					" column type:" << rgColumnDesc[i].pwszTypeName << "\n";

		CHECK(AddColumnAndCheck(&m_pTable->GetTableID(), &rgColumnDesc[i], 
			&pColumnID), S_OK);

		CHECK(m_pTable->DropTable(), S_OK);
		ReleaseDBID(pColumnID);
		pColumnID = NULL;
	}

	ReleaseColumnDesc(rgColumnDesc, cColumnDesc);
	TRETURN
}
// }}


// {{ TCW_VAR_PROTOTYPE(14)
//*-----------------------------------------------------------------------
// @mfunc Add a column for each known type; ulColumnsize == 0 => S_OK
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCAddColumn::Variation_14()
{
	TBEGIN
	DBID			*pColumnID = NULL;
	DBORDINAL		i;
	DBCOLUMNDESC	*pColumnDesc = NULL;
	DBCOLUMNDESC	*rgColumnDesc	= NULL;
	DBORDINAL		cColumnDesc		= 0;

	DuplicateColumnDesc(m_rgColumnDesc, m_cColumnDesc, &rgColumnDesc);
	cColumnDesc = m_cColumnDesc;
	ReleaseAllColumnPropSets(rgColumnDesc, cColumnDesc);
	DuplicateColumnDesc(rgColumnDesc, 1, &pColumnDesc);
	PROVIDER_FREE(pColumnDesc->dbcid.uName.pwszName);
	pColumnDesc->dbcid.uName.pwszName = wcsDuplicate(L"FirstColumn");
	SetZeroColSize(rgColumnDesc, cColumnDesc);
	// for each type in DBCOLUMNDESC, add a column with maximum column size
	m_pTable->SetColumnDesc(NULL);
	m_pTable->SetColumnDesc(pColumnDesc, 1);
	m_pTable->SetBuildColumnDesc(FALSE);

	for (i=0; i<cColumnDesc; i++)
	{
		// create a table with a single column, equal to the first one in the row
		CHECK(m_hr = m_pTable->CreateTable(0, 0), S_OK);

		if (FAILED(m_hr))
			continue;

		// try to add a column from rgColumnDesc[i]
		odtLog <<	"column name:" << rgColumnDesc[i].dbcid.uName.pwszName << 
					" column type:" << rgColumnDesc[i].pwszTypeName << "\n";

		CHECK(AddColumnAndCheck(&m_pTable->GetTableID(), &rgColumnDesc[i], 
			&pColumnID), S_OK);

		CHECK(m_pTable->DropTable(), S_OK);
		ReleaseDBID(pColumnID);
		pColumnID = NULL;
	}

	ReleaseColumnDesc(rgColumnDesc, cColumnDesc);
	TRETURN
}
// }}


// {{ TCW_VAR_PROTOTYPE(15)
//--------------------------------------------------------------------
// @mfunc Add a column for each provider type (table is populated) => S_OK
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCAddColumn::Variation_15()
{
	TBEGIN
	DBID			*pColumnID = NULL;
	DBORDINAL		i;
	DBCOLUMNDESC	*pColumnDesc = NULL;
	DBCOLUMNDESC	*rgColumnDesc	= NULL;
	DBORDINAL		cColumnDesc		= 0;

	DuplicateColumnDesc(m_rgColumnDesc, m_cColumnDesc, &rgColumnDesc);
	cColumnDesc = m_cColumnDesc;
	ReleaseAllColumnPropSets(rgColumnDesc, cColumnDesc);
	DuplicateColumnDesc(rgColumnDesc, 1, &pColumnDesc);
	PROVIDER_FREE(pColumnDesc->dbcid.uName.pwszName);
	pColumnDesc->dbcid.uName.pwszName = wcsDuplicate(L"FirstColumn");

	m_pTable->SetColumnDesc(NULL);
	m_pTable->SetColumnDesc(pColumnDesc, 1);
	m_pTable->SetBuildColumnDesc(FALSE);

	for (i=0; i<cColumnDesc; i++)
	{
		// try to add a column from rgColumnDesc[i]
		odtLog <<	"column name:" << rgColumnDesc[i].dbcid.uName.pwszName << 
				" column type:" << rgColumnDesc[i].pwszTypeName << "\n";

		// create a popoulated table 
		if (!CHECK(m_pTable->CreateTable(10, 0), S_OK))
			continue;

		CHECK(AddColumnAndCheck(&m_pTable->GetTableID(), &rgColumnDesc[i], 
				&pColumnID), S_OK);

		ReleaseDBID(pColumnID);
		pColumnID = NULL;
		CHECK(m_pTable->DropTable(), S_OK);
	}

	ReleaseColumnDesc(rgColumnDesc, cColumnDesc);
	TRETURN
}
// }}


// {{ TCW_VAR_PROTOTYPE(16)
//*-----------------------------------------------------------------------
// @mfunc Precision testing
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCAddColumn::Variation_16()
{
	TBEGIN
	DBID			*pColumnID = NULL;
	DBORDINAL		i;
	WCHAR			*pwszColumnName = NULL;
	BYTE			precision, p[6];
	ULONG			nmax = 6;
	WCHAR			*prefix[]={L"zero", L"one", L"half", L"max", L"big", L"extra"};
	HRESULT			hres;
	DBCOLUMNDESC	*rgColDesc = NULL;
	DBCOLUMNDESC	*rgColumnDesc	= NULL;
	DBORDINAL		cColumnDesc		= 0;

	DuplicateColumnDesc(m_rgColumnDesc, m_cColumnDesc, &rgColumnDesc);
	cColumnDesc = m_cColumnDesc;
	ReleaseAllColumnPropSets(rgColumnDesc, cColumnDesc);
	DuplicateColumnDesc(rgColumnDesc, 1, &rgColDesc);
	m_pTable->SetColumnDesc(rgColDesc, 1);
	m_pTable->SetBuildColumnDesc(FALSE);
	SAFE_FREE(rgColDesc[0].dbcid.uName.pwszName);
	rgColDesc[0].dbcid.uName.pwszName = wcsDuplicate(L"initialColumn");

	// for each type in DBCOLUMNDESC, add a column with different precision value
	for (i=0; i<cColumnDesc; i++)
	{

		// try to add a column with different precision values
		odtLog <<	"column name:" << rgColumnDesc[i].dbcid.uName.pwszName << 
					" column type:" << rgColumnDesc[i].pwszTypeName << "\n";
		precision = rgColumnDesc[i].bPrecision; // BuildColumnDesc puts max val in bPrecision!
		p[0] = 0;
		p[1] = 1;
		p[2] = precision/2;
		p[3] = precision;
		if (precision > 254)
			nmax = 4;
		p[4] = precision+1;
		p[5] = (ULONG)precision+10>255? 255: precision+10;

		pwszColumnName = rgColumnDesc[i].dbcid.uName.pwszName;
		rgColumnDesc[i].dbcid.uName.pwszName = NULL;
		
		rgColumnDesc[i].bScale = 0;
		rgColumnDesc[i].ulColumnSize = 0;
		
		for (ULONG j=0; j<nmax; j++)
		{
			odtLog << "\t" << p[j];
			if (!CHECK(m_hr = m_pTable->CreateTable(0, 0), S_OK))
				continue;

			// if needed you can limit wcscat with the max length for col size
			rgColumnDesc[i].dbcid.uName.pwszName = (WCHAR*) PROVIDER_ALLOC( sizeof(WCHAR) * m_cMaxColName);
			wcscpy(rgColumnDesc[i].dbcid.uName.pwszName, prefix[j]);
			wcsncat(rgColumnDesc[i].dbcid.uName.pwszName, pwszColumnName, m_cMaxColName-wcslen(prefix[j]));
			rgColumnDesc[i].bPrecision = p[j];
			hres = S_OK;
			if (rgColumnDesc[i].wType == DBTYPE_NUMERIC && ((j>3) || (j==0)) )
				hres = DB_E_BADPRECISION;

			CHECK(AddColumnAndCheck(&m_pTable->GetTableID(), 
							&rgColumnDesc[i], &pColumnID), hres);

			SAFE_FREE(rgColumnDesc[i].dbcid.uName.pwszName);
			rgColumnDesc[i].dbcid.uName.pwszName = NULL;
			CHECK(m_pTable->DropTable(), S_OK);
			ReleaseDBID(pColumnID);
			pColumnID = NULL;
		}
		odtLog << "\n";
	}

	ReleaseColumnDesc(rgColumnDesc, cColumnDesc);
	TRETURN
}
// }}


// {{ TCW_VAR_PROTOTYPE(17)
//*-----------------------------------------------------------------------
// @mfunc Scale testing
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCAddColumn::Variation_17()
{
	TBEGIN
	DBID			*pColumnID = NULL;
	DBORDINAL		i;
	WCHAR			*pwszName;
	DBCOLUMNDESC	*pColumnDesc = NULL;
	DBCOLUMNDESC	*rgColumnDesc	= NULL;
	DBORDINAL		cColumnDesc		= 0;

	DuplicateColumnDesc(m_rgColumnDesc, m_cColumnDesc, &rgColumnDesc);
	cColumnDesc = m_cColumnDesc;
	ReleaseAllColumnPropSets(rgColumnDesc, cColumnDesc);
	DuplicateColumnDesc(rgColumnDesc, 1, &pColumnDesc);
	//SetZeroColSize(rgColumnDesc, cColumnDesc);
	PROVIDER_FREE(pColumnDesc->dbcid.uName.pwszName);
	pColumnDesc->dbcid.uName.pwszName = wcsDuplicate(L"Initial_column");
	// create a table with a single column, equal to the first one in the row
	m_pTable->SetColumnDesc(NULL);	// so that m_pTable->rgColumnDesc will not be deallocated next
	m_pTable->SetColumnDesc(pColumnDesc, 1);
	m_pTable->SetBuildColumnDesc(FALSE);

	// for each type in DBCOLUMNDESC, add a column with different precision value
	for (i=0; i<cColumnDesc; i++)
	{
		CHECK(m_hr = m_pTable->CreateTable(0, 0), S_OK);
		if (!SUCCEEDED(m_hr))
			continue;

		odtLog <<	"column name: " << rgColumnDesc[i].dbcid.uName.pwszName << 
					" column type: " << rgColumnDesc[i].pwszTypeName << "\n";

		if (	rgColumnDesc[i].wType == DBTYPE_NUMERIC 
			||	rgColumnDesc[i].wType == DBTYPE_DECIMAL
			||	rgColumnDesc[i].wType == DBTYPE_VARNUMERIC )
		{
			const int nScales = 7;
			BYTE	smax, smin, p[nScales], s[nScales], precision;
			ULONG	nmax = 1;
			WCHAR	*prefix[]={L"zero", L"min", L"half", L"max", L"maxpp", L"prec", L"extra_prec"};
			HRESULT	hres[nScales] = {S_OK, S_OK, S_OK, S_OK, S_OK, S_OK, S_OK};
			CCol	col = GetType(GetColumnTypeName(&rgColumnDesc[i]), rgColumnDesc[i].wType);

			// try to add a column with different scale values
			smin = (BYTE)col.GetMinScale();
			smax = (BYTE)col.GetMaxScale();
			precision = (BYTE)col.GetPrecision();
			for (ULONG k=0; k<nScales; p[k++]=precision);
			s[0] = 0;
			hres[0] = (smin==0)? S_OK: DB_E_BADSCALE;
			if (smin > 0)
			{
				s[1]	= smin;
				nmax++;
			}
			s[nmax++] = (smin+smax)/2;
			s[nmax++] = smax;
			if (smax < 255)
			{
				s[nmax]			= smax+1;
				hres[nmax++]	= DB_E_BADSCALE;
				// check matching the precision
				s[nmax]		= precision;
				hres[nmax]	= (precision>smax) ? DB_E_BADSCALE: S_OK;
				nmax++;
				s[nmax]		= p[nmax]+1;
				hres[nmax++]= DB_E_BADSCALE;
			}

			pwszName = rgColumnDesc[i].dbcid.uName.pwszName;
			rgColumnDesc[i].dbcid.uName.pwszName = NULL;	// protection for inside the loop!
			for (ULONG j=0; j<nmax; j++)
			{
				odtLog << "\t" << s[j];

				// if needed you can limit wcscat with the max length for col size
				if (rgColumnDesc[i].dbcid.uName.pwszName)
					SAFE_FREE(rgColumnDesc[i].dbcid.uName.pwszName);
				rgColumnDesc[i].dbcid.uName.pwszName = (WCHAR*) PROVIDER_ALLOC( sizeof(WCHAR) * m_cMaxColName);
				wcscpy(rgColumnDesc[i].dbcid.uName.pwszName, prefix[j]);
				wcsncat(rgColumnDesc[i].dbcid.uName.pwszName, pwszName, m_cMaxColName-wcslen(prefix[j]));
				rgColumnDesc[i].bPrecision = p[j];
				rgColumnDesc[i].bScale = s[j];

				CHECK(AddColumnAndCheck(&m_pTable->GetTableID(), 
					&rgColumnDesc[i], &pColumnID), hres[j]);
				ReleaseDBID(pColumnID);
				pColumnID = NULL;
			}
			odtLog << "\n";
			SAFE_FREE(pwszName);
		}
		else
		{
			rgColumnDesc[i].bScale = 128;
			CHECK(AddColumnAndCheck(&m_pTable->GetTableID(), 
						&rgColumnDesc[i], &pColumnID), S_OK);
			ReleaseDBID(pColumnID);
			pColumnID = NULL;
		}
		CHECK(m_pTable->DropTable(), S_OK);
	}

	ReleaseColumnDesc(rgColumnDesc, cColumnDesc);
	m_pTable->SetNoOfColumnDesc(1);
	TRETURN
}
// }}


// {{ TCW_VAR_PROTOTYPE(18)
//*-----------------------------------------------------------------------
// @mfunc Invalid value for the property of a column => DB_E_ERRORSOCCURRED
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCAddColumn::Variation_18()
{
	TBEGIN
	DBID			*pColumnID = NULL;
	DBPROPID		dwPropID = DBPROP_COL_UNIQUE;
	DBCOLUMNDESC	*rgColumnDesc	= NULL;
	DBORDINAL		cColumnDesc		= 0;

	DuplicateColumnDesc(m_rgColumnDesc, m_cColumnDesc, &rgColumnDesc);
	cColumnDesc = m_cColumnDesc;
	ReleaseAllColumnPropSets(rgColumnDesc, cColumnDesc);
	m_pTable->SetBuildColumnDesc(FALSE);
	m_pTable->SetColumnDesc(rgColumnDesc, cColumnDesc-1);

	TESTC_(m_pTable->CreateTable(0, 0), S_OK);

	// try to add a column with a bad property value (prop of a different type than expected)
	SetProperty(&rgColumnDesc[cColumnDesc-1].rgPropertySets, 
				&rgColumnDesc[cColumnDesc-1].cPropertySets, 
				dwPropID, 
				VT_I2, (LPVOID)12, 
				DBPROPOPTIONS_REQUIRED);

	TESTC_(AddColumnAndCheck(&m_pTable->GetTableID(), 
				&rgColumnDesc[cColumnDesc-1], &pColumnID), DB_E_ERRORSOCCURRED);
	TESTC(VerifyPropStatus(rgColumnDesc[cColumnDesc-1].cPropertySets, 
		rgColumnDesc[cColumnDesc-1].rgPropertySets, dwPropID, DBPROPSET_COLUMN, 
		DBPROPSTATUS_BADVALUE));

CLEANUP:
	CHECK(m_pTable->DropTable(), S_OK);
	m_pTable->SetNoOfColumnDesc(cColumnDesc);
	ReleaseDBID(pColumnID);
	TRETURN
}
// }}


// {{ TCW_VAR_PROTOTYPE(19)
//*-----------------------------------------------------------------------
// @mfunc Non-column property => DBPROPSTATUS_NOTSUPPORTED
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCAddColumn::Variation_19()
{
	TBEGIN
	DBID			*pColumnID = NULL;
	DBPROPID		dwPropID = DBPROP_COL_UNIQUE;
	DBCOLUMNDESC	*rgColumnDesc	= NULL;
	DBORDINAL		cColumnDesc		= 0;

	DuplicateColumnDesc(m_rgColumnDesc, m_cColumnDesc, &rgColumnDesc);
	cColumnDesc = m_cColumnDesc;
	ReleaseAllColumnPropSets(rgColumnDesc, cColumnDesc);
	m_pTable->SetBuildColumnDesc(FALSE);
	m_pTable->SetColumnDesc(rgColumnDesc, cColumnDesc-1);

	TESTC_(m_pTable->CreateTable(0, 0), S_OK);
		
	// try to add a column with a bad property guid (DBPROPSET_INDEX)
	SetProperty(
		&rgColumnDesc[cColumnDesc-1].rgPropertySets, &rgColumnDesc[cColumnDesc-1].cPropertySets,
		dwPropID, 
		VT_BOOL, (LPVOID)VARIANT_TRUE, 
		DBPROPOPTIONS_OPTIONAL, DB_NULLID, DBPROPSET_INDEX);
	
	TESTC_(AddColumnAndCheck(&m_pTable->GetTableID(), 
			&rgColumnDesc[cColumnDesc-1], &pColumnID), DB_S_ERRORSOCCURRED);
	TESTC(VerifyPropStatus(rgColumnDesc[cColumnDesc-1].cPropertySets, 
		rgColumnDesc[cColumnDesc-1].rgPropertySets, dwPropID, DBPROPSET_INDEX, DBPROPSTATUS_NOTSUPPORTED));

CLEANUP:
	CHECK(m_pTable->DropTable(), S_OK);
	m_pTable->SetNoOfColumnDesc(cColumnDesc);
	ReleaseDBID(pColumnID);
	TRETURN
}
// }}


// {{ TCW_VAR_PROTOTYPE(20)
//*-----------------------------------------------------------------------
// @mfunc Inexistent property => DBPROPSTATUS_NOTSUPPORTED
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCAddColumn::Variation_20()
{
	TBEGIN
	DBID			*pColumnID = NULL;
	DBCOLUMNDESC	*rgColumnDesc	= NULL;
	DBORDINAL		cColumnDesc		= 0;

	DuplicateColumnDesc(m_rgColumnDesc, m_cColumnDesc, &rgColumnDesc);
	cColumnDesc = m_cColumnDesc;
	ReleaseAllColumnPropSets(rgColumnDesc, cColumnDesc);
	m_pTable->SetBuildColumnDesc(FALSE);
	m_pTable->SetColumnDesc(rgColumnDesc, cColumnDesc-1);

	TESTC_(m_pTable->CreateTable(0, 0), S_OK); 

	// try to add a column with a bad property id 
	SetProperty(&rgColumnDesc[cColumnDesc-1].rgPropertySets, 
		&rgColumnDesc[cColumnDesc-1].cPropertySets, 0xffffffff, VT_BOOL, (LPVOID)VARIANT_TRUE);

	TESTC_(AddColumnAndCheck(&m_pTable->GetTableID(), 
			&rgColumnDesc[cColumnDesc-1], &pColumnID), DB_S_ERRORSOCCURRED);

	TESTC(VerifyPropStatus(rgColumnDesc[cColumnDesc-1].cPropertySets, 
		rgColumnDesc[cColumnDesc-1].rgPropertySets, 0xffffffff, 
		DBPROPSET_COLUMN, DBPROPSTATUS_NOTSUPPORTED));

CLEANUP:
	CHECK(m_pTable->DropTable(), S_OK);
	m_pTable->SetNoOfColumnDesc(cColumnDesc);
	ReleaseDBID(pColumnID);
	TRETURN
}
// }}


// {{ TCW_VAR_PROTOTYPE(21)
//*-----------------------------------------------------------------------
// @mfunc Bad option => DBPROPSTATUS_BADOPTION
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCAddColumn::Variation_21()
{
	TBEGIN
	DBID			*pColumnID		= NULL;
	DBPROPID		dwPropID		= DBPROP_COL_NULLABLE;
	DBCOLUMNDESC	*rgColumnDesc	= NULL;
	DBORDINAL		cColumnDesc		= 0;

	DuplicateColumnDesc(m_rgColumnDesc, m_cColumnDesc, &rgColumnDesc);
	cColumnDesc = m_cColumnDesc;
	ReleaseAllColumnPropSets(rgColumnDesc, cColumnDesc);
	m_pTable->SetBuildColumnDesc(FALSE);
	m_pTable->SetColumnDesc(rgColumnDesc, cColumnDesc-1);

	TESTC_(m_pTable->CreateTable(0, 0), S_OK);
	
	// try to add a column with a bad option
	SetProperty(&rgColumnDesc[cColumnDesc-1].rgPropertySets, &rgColumnDesc[cColumnDesc-1].cPropertySets,
		dwPropID, 
		VT_BOOL, (LPVOID)VARIANT_TRUE, 
		0xf0);
	
	TESTC_(AddColumnAndCheck(&m_pTable->GetTableID(), 
				&rgColumnDesc[cColumnDesc-1], &pColumnID), DB_E_ERRORSOCCURRED);

	TESTC(VerifyPropStatus(rgColumnDesc[cColumnDesc-1].cPropertySets,
		rgColumnDesc[cColumnDesc-1].rgPropertySets, dwPropID,
		DBPROPSET_COLUMN,DBPROPSTATUS_BADOPTION));

CLEANUP:
	CHECK(m_pTable->DropTable(), S_OK);
	m_pTable->SetNoOfColumnDesc(cColumnDesc);
	ReleaseDBID(pColumnID);
	TRETURN
}
// }}


// {{ TCW_VAR_PROTOTYPE(22)
//*-----------------------------------------------------------------------
// @mfunc Conflicting property => DBPROPSTATUS_CONFLICTING
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCAddColumn::Variation_22()
{
	TBEGIN
	DBID			*pColumnID = NULL;
	DBORDINAL		i, nCol;
	CCol			col;
	DBCOLUMNDESC	*rgColumnDesc	= NULL;
	DBORDINAL		cColumnDesc		= 0;
	ULONG			nConfStatus		= 0;
	ULONG			nOKStatus		= 0;

	TESTC_PROVIDER(SettableProperty(DBPROP_COL_PRIMARYKEY, DBPROPSET_COLUMN)
		&&	SettableProperty(DBPROP_COL_NULLABLE, DBPROPSET_COLUMN));

	DuplicateColumnDesc(m_rgColumnDesc, m_cColumnDesc, &rgColumnDesc);
	cColumnDesc = m_cColumnDesc;
	ReleaseAllColumnPropSets(rgColumnDesc, cColumnDesc);
	m_pTable->SetBuildColumnDesc(FALSE);
	m_pTable->SetColumnDesc(rgColumnDesc, cColumnDesc);
	nCol = cColumnDesc;
	for (i=0; i< cColumnDesc; i++)
	{
		col = GetType(GetColumnTypeName(&rgColumnDesc[i]), rgColumnDesc[i].wType);
		if (col.GetNullable()!=0)
			nCol = i;
	}

	TESTC(nCol < cColumnDesc);

	TESTC_(m_pTable->CreateTable(0, 0), S_OK);
	// try to add a column with conflicting properties 
	PROVIDER_FREE(rgColumnDesc[nCol].dbcid.uName.pwszName);
	rgColumnDesc[nCol].dbcid.uName.pwszName = wcsDuplicate(L"MyColumn");
	SetProperty(&rgColumnDesc[nCol].rgPropertySets, &rgColumnDesc[nCol].cPropertySets,
		DBPROP_COL_PRIMARYKEY, VT_BOOL, (LPVOID)VARIANT_TRUE, DBPROPOPTIONS_REQUIRED);
	SetProperty(&rgColumnDesc[nCol].rgPropertySets, &rgColumnDesc[nCol].cPropertySets,
		DBPROP_COL_NULLABLE, VT_BOOL, (LPVOID)VARIANT_TRUE, DBPROPOPTIONS_REQUIRED);
	
	TESTC_(AddColumnAndCheck(&m_pTable->GetTableID(), 
				&rgColumnDesc[nCol], &pColumnID), DB_E_ERRORSOCCURRED);
	
	if (DBPROPSTATUS_CONFLICTING == rgColumnDesc[nCol].rgPropertySets[0].rgProperties[0].dwStatus)
		nConfStatus++;
	else 
	{
		TESTC(DBPROPSTATUS_OK == rgColumnDesc[nCol].rgPropertySets[0].rgProperties[0].dwStatus);
	}

	if (DBPROPSTATUS_CONFLICTING == rgColumnDesc[nCol].rgPropertySets[0].rgProperties[1].dwStatus)
		nConfStatus++;
	else 
	{
		TESTC(DBPROPSTATUS_OK == rgColumnDesc[nCol].rgPropertySets[0].rgProperties[1].dwStatus);
	}

	TESTC(0 < nConfStatus);

CLEANUP:
	CHECK(m_pTable->DropTable(), S_OK);
	ReleaseDBID(pColumnID);
	TRETURN
}
// }}


// {{ TCW_VAR_PROTOTYPE(23)
//--------------------------------------------------------------------
// @mfunc Bad column ID for a property => ignored
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCAddColumn::Variation_23()
{
	TBEGIN
	DBID			*pColumnID		= NULL;
	DBID			colID;
	DBCOLUMNDESC	*rgColumnDesc	= NULL;
	DBORDINAL		cColumnDesc		= 0;
	DBORDINAL		cCol;
	CCol			col;
	BOOL			fFound			= FALSE;
	BOOL			fExists;

	DuplicateColumnDesc(m_rgColumnDesc, m_cColumnDesc, &rgColumnDesc);
	cColumnDesc = m_cColumnDesc;
	for (cCol=0; cCol < m_cColumnDesc; cCol++)
	{
		col = GetType(GetColumnTypeName(&rgColumnDesc[cCol]), rgColumnDesc[cCol].wType, &fExists);
		fFound = fExists && 1 == col.GetNullable();
		break;
	}

	TESTC_PROVIDER(fFound && SupportedProperty(DBPROP_COL_NULLABLE, DBPROPSET_COLUMN));

	ReleaseAllColumnPropSets(rgColumnDesc, cColumnDesc);
	m_pTable->SetColumnDesc(rgColumnDesc, cColumnDesc);
	m_pTable->SetBuildColumnDesc(FALSE);

	TESTC_(m_pTable->CreateTable(0, 0), S_OK);

	// try to add a column with a property that set coldid to smthg different from DB_NULLID
	colID.eKind = DBKIND_NAME;
	colID.uName.pwszName = wcsDuplicate(L"bogus");
	SetProperty(&rgColumnDesc[cCol].rgPropertySets, &rgColumnDesc[cCol].cPropertySets,
		DBPROP_COL_NULLABLE, VT_BOOL, (LPVOID)VARIANT_TRUE, DBPROPOPTIONS_OPTIONAL, colID);
	if (DBKIND_NAME == rgColumnDesc[cCol].dbcid.eKind && rgColumnDesc[cCol].dbcid.uName.pwszName)
		PROVIDER_FREE(rgColumnDesc[cCol].dbcid.uName.pwszName);
	rgColumnDesc[cCol].dbcid.eKind = DBKIND_NAME;
	rgColumnDesc[cCol].dbcid.uName.pwszName = wcsDuplicate(L"ExtraColumn");
		
	TESTC_(AddColumnAndCheck(&m_pTable->GetTableID(), &rgColumnDesc[cCol], 
		&pColumnID), S_OK);

	TESTC(VerifyPropStatus(rgColumnDesc[cCol].cPropertySets,
		rgColumnDesc[cCol].rgPropertySets, DBPROP_COL_NULLABLE,
		DBPROPSET_COLUMN, DBPROPSTATUS_OK));

CLEANUP:
	ReleaseDBID(pColumnID);
	CHECK(m_pTable->DropTable(), S_OK);
	TRETURN
}
// }}


// {{ TCW_VAR_PROTOTYPE(24)
//*-----------------------------------------------------------------------
// @mfunc Bad column type (wType in DBCOLUMNDESC)
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCAddColumn::Variation_24()
{
	TBEGIN
	DBID			*pColumnID = NULL;
	DBCOLUMNDESC	*rgColumnDesc	= NULL;
	DBORDINAL		cColumnDesc		= 0;

	DuplicateColumnDesc(m_rgColumnDesc, m_cColumnDesc, &rgColumnDesc);
	cColumnDesc = m_cColumnDesc;
	ReleaseAllColumnPropSets(rgColumnDesc, cColumnDesc);
	m_pTable->SetBuildColumnDesc(FALSE);
	m_pTable->SetColumnDesc(rgColumnDesc, cColumnDesc-1);

	TESTC_(m_pTable->CreateTable(10, 0), S_OK);
	// try to add a column with a bad wType
	PROVIDER_FREE(rgColumnDesc[cColumnDesc-1].pwszTypeName);
	rgColumnDesc[cColumnDesc-1].pwszTypeName = NULL;
	rgColumnDesc[cColumnDesc-1].wType = 0xFFFF;
	
	TESTC_(AddColumnAndCheck(&m_pTable->GetTableID(), 
				&rgColumnDesc[cColumnDesc-1], &pColumnID), DB_E_BADTYPE);

CLEANUP:
	ReleaseDBID(pColumnID);
	CHECK(m_pTable->DropTable(), S_OK);
	m_pTable->SetNoOfColumnDesc(cColumnDesc);
	TRETURN
}
// }}


// {{ TCW_VAR_PROTOTYPE(25)
//*-----------------------------------------------------------------------
// @mfunc Invalid provider type name for a column => DB_E_BADTYPE
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCAddColumn::Variation_25()
{
	TBEGIN
	DBID			*pColumnID		= NULL;
	DBCOLUMNDESC	*rgColumnDesc	= NULL;
	DBORDINAL		cColumnDesc		= 0;

	DuplicateColumnDesc(m_rgColumnDesc, m_cColumnDesc, &rgColumnDesc);
	cColumnDesc = m_cColumnDesc;
	ReleaseAllColumnPropSets(rgColumnDesc, cColumnDesc);
	m_pTable->SetBuildColumnDesc(FALSE);
	m_pTable->SetColumnDesc(rgColumnDesc, cColumnDesc-1);

	TESTC_(m_pTable->CreateTable(10, 0), S_OK);
	// try to add a column with a bad wType
	PROVIDER_FREE(rgColumnDesc[cColumnDesc-1].pwszTypeName);
	rgColumnDesc[cColumnDesc-1].pwszTypeName = wcsDuplicate(L"New_type_name");
	
	TESTC_(AddColumnAndCheck(&m_pTable->GetTableID(), 
				&rgColumnDesc[cColumnDesc-1], &pColumnID), DB_E_BADTYPE);


CLEANUP:
	CHECK(m_pTable->DropTable(), S_OK);
	m_pTable->SetNoOfColumnDesc(cColumnDesc);
	ReleaseDBID(pColumnID);
	TRETURN
}
// }}


// {{ TCW_VAR_PROTOTYPE(26)
//*-----------------------------------------------------------------------
// @mfunc NULL ppColumnDesc => S_OK
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCAddColumn::Variation_26()
{
	TBEGIN
	DBCOLUMNDESC	*rgColumnDesc	= NULL;
	DBORDINAL		cColumnDesc		= 0;

	DuplicateColumnDesc(m_rgColumnDesc, m_cColumnDesc, &rgColumnDesc);
	cColumnDesc = m_cColumnDesc;
	ReleaseAllColumnPropSets(rgColumnDesc, cColumnDesc);
	m_pTable->SetBuildColumnDesc(FALSE);
	m_pTable->SetColumnDesc(rgColumnDesc, cColumnDesc-1);

	TESTC_(m_pTable->CreateTable(0, 0), S_OK); 

	// try to add a column with a bad wType
	TESTC_(AddColumnAndCheck(&m_pTable->GetTableID(), 
			&rgColumnDesc[cColumnDesc-1], NULL), S_OK);

CLEANUP:
	CHECK(m_pTable->DropTable(), S_OK);
	m_pTable->SetNoOfColumnDesc(cColumnDesc);
	TRETURN
}
// }}


// {{ TCW_VAR_PROTOTYPE(27)
//*-----------------------------------------------------------------------
// @mfunc Autoincrementable column - DBPROP_COL_AUTOINCREMENT
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCAddColumn::Variation_27()
{
	TBEGIN
	DBCOLUMNDESC	*pColumnDesc = NULL;
	DBORDINAL		i;
	CCol			col;
	HRESULT			hres1;	// for DBPROP_COL_AUTOINCREMENT set to VARIANT_TRUE
	HRESULT			hres2;	// for DBPROP_COL_AUTOINCREMENT set to VARIANT_FALSE
	HRESULT			hr;
	BOOL			fReadOnlyAutoInc;
	DBCOLUMNDESC	*rgColumnDesc	= NULL;
	DBORDINAL		cColumnDesc		= 0;
	BOOL			fSupported		= TRUE;
	ULONG			ulStatus,
					cPropSet,
					cProp;

	DuplicateColumnDesc(m_rgColumnDesc, m_cColumnDesc, &rgColumnDesc);
	cColumnDesc = m_cColumnDesc;
	ReleaseAllColumnPropSets(rgColumnDesc, cColumnDesc);
	m_pTable->SetBuildColumnDesc(FALSE);

	fReadOnlyAutoInc = !SettableProperty(DBPROP_COL_AUTOINCREMENT, DBPROPSET_COLUMN);
	fSupported		 = SupportedProperty(DBPROP_COL_AUTOINCREMENT, DBPROPSET_COLUMN);
	if (!fSupported)
		odtLog << "DBPROP_COL_AUTOINCREMENT is NOT SUPPORTED!\n";
	DuplicateColumnDesc(&rgColumnDesc[0], 1, &pColumnDesc);

	SAFE_FREE(pColumnDesc->dbcid.uName.pwszName)
	pColumnDesc->dbcid.uName.pwszName = wcsDuplicate(L"First_column");
	m_pTable->SetColumnDesc(pColumnDesc, 1);

	for (i=0; i<cColumnDesc; i++)
	{
		col = GetType(GetColumnTypeName(&rgColumnDesc[i]), rgColumnDesc[i].wType);
		if (fSupported)
		{
			hres1 = (col.CanAutoInc()) ? S_OK : DB_E_ERRORSOCCURRED;
			hres2 = (!col.CanAutoInc() || !fReadOnlyAutoInc) ? S_OK : DB_E_ERRORSOCCURRED;
			odtLog	<< GetColumnTypeName(&rgColumnDesc[i]) 
					<< ((col.CanAutoInc()) ? " is AUTOINCREMENTABLE\n" : " is NOT autoincrementable\n");
		}
		else
		{
			hres1 = hres2 = DB_E_ERRORSOCCURRED;
		}

		if (!CHECK(m_pTable->CreateTable(0, 0), S_OK)) 
			continue;

		// try to add the column described by rgColumnDesc[i] to the table
		// and set it as an AUTOINCREMENT COLUMN
		SetProperty(&rgColumnDesc[i].rgPropertySets, &rgColumnDesc[i].cPropertySets,
			DBPROP_COL_AUTOINCREMENT, VT_BOOL, (LPVOID)VARIANT_TRUE, DBPROPOPTIONS_REQUIRED,
			DB_NULLID, DBPROPSET_COLUMN, &cPropSet, &cProp);
		rgColumnDesc[i].bScale = 0;

		CHECK(hr = AddColumnAndCheck(&m_pTable->GetTableID(), 
					&rgColumnDesc[i], NULL), hres1);
		
		odtLog << (SUCCEEDED(hr) ? "\tautoinc column added\n" : "\tautoinc column could not be added\n");
		//check the state
		ulStatus = rgColumnDesc[i].rgPropertySets[cPropSet].rgProperties[cProp].dwStatus;
		if (S_OK == hr)
		{
			COMPARE(ulStatus, DBPROPSTATUS_OK);
			COMPARE(fSupported, TRUE);
			COMPARE(col.CanAutoInc(), TRUE);
		}
		else
		{
			CHECK(hr, DB_E_ERRORSOCCURRED);

			if (!fSupported)
				COMPARE(ulStatus, DBPROPSTATUS_NOTSUPPORTED);
			else if (fReadOnlyAutoInc)
				COMPARE(ulStatus, DBPROPSTATUS_NOTSETTABLE);
			else
				COMPARE(ulStatus, DBPROPSTATUS_BADVALUE);
		}

		ReleaseAllColumnPropSets(&rgColumnDesc[i], 1);

		CHECK(m_pTable->DropTable(), S_OK);
		
		if (!CHECK(m_pTable->CreateTable(0, 0), S_OK))
			continue;

		// try to add the column described by rgColumnDesc[i] to the table
		// and set it as an non autoincrement column
		SetProperty(&rgColumnDesc[i].rgPropertySets, &rgColumnDesc[i].cPropertySets,
			DBPROP_COL_AUTOINCREMENT, VT_BOOL, (LPVOID)VARIANT_FALSE, DBPROPOPTIONS_REQUIRED);
		rgColumnDesc[i].bScale = 0;
		CHECK(hr = AddColumnAndCheck(&m_pTable->GetTableID(), 
					&rgColumnDesc[i], NULL), hres2);

		odtLog << (SUCCEEDED(hr) ? "\tNOT autoinc column added\n" : "\tNOT autoinc column could not be added\n");
		// check the returned status
		ulStatus = rgColumnDesc[i].rgPropertySets[0].rgProperties[0].dwStatus;

		if (S_OK == hr)
		{
			COMPARE(ulStatus, DBPROPSTATUS_OK);
			COMPARE(fSupported, TRUE);
		}
		else
		{
			CHECK(hr, DB_E_ERRORSOCCURRED);
			COMPARE(!col.CanAutoInc(), TRUE);

			if (!fSupported)
				COMPARE(ulStatus, DBPROPSTATUS_NOTSUPPORTED);
			else if (fReadOnlyAutoInc)
				COMPARE(ulStatus, DBPROPSTATUS_NOTSETTABLE);
			else
				COMPARE(ulStatus, DBPROPSTATUS_BADVALUE);
		}

		ReleaseAllColumnPropSets(&rgColumnDesc[i], 1);
		CHECK(m_pTable->DropTable(), S_OK);
	}
	ReleaseColumnDesc(rgColumnDesc, cColumnDesc);
	TRETURN
}
// }}


// {{ TCW_VAR_PROTOTYPE(28)
//*-----------------------------------------------------------------------
// @mfunc DBPROP_COL_DEFAULT
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCAddColumn::Variation_28()
{
	TBEGIN
	DBCOLUMNDESC			*pColumnDesc=NULL;
	DBORDINAL				i;
	HRESULT					hr;
	VARIANT					value;
	DBCOLUMNDESC			*rgColumnDesc	= NULL;
	DBORDINAL				cColumnDesc		= 0;
	CTable					*pTable = new CTable(m_pThisTestModule->m_pIUnknown2, (LPWSTR)gwszModuleName);
	CList<WCHAR *,WCHAR *>	NativeTypesList;
	CList<DBTYPE,DBTYPE>	ProviderTypesList;
	BOOL					fSettable = TRUE;
	BOOL					fSupported = TRUE;
	ULONG					ulStatus;

	pTable->CreateTypeColInfo(NativeTypesList, ProviderTypesList);
	DuplicateColumnDesc(m_rgColumnDesc, m_cColumnDesc, &rgColumnDesc);
	cColumnDesc = m_cColumnDesc;
	ReleaseAllColumnPropSets(rgColumnDesc, cColumnDesc);
	m_pTable->SetBuildColumnDesc(FALSE);
	DuplicateColumnDesc(&rgColumnDesc[0], 1, &pColumnDesc);
	PROVIDER_FREE(pColumnDesc->dbcid.uName.pwszName);
	pColumnDesc->dbcid.uName.pwszName = wcsDuplicate(L"First_column");
	ASSERT(pColumnDesc->dbcid.uName.pwszName);
	m_pTable->SetColumnDesc(pColumnDesc, 1);

	if (!SupportedProperty(DBPROP_COL_DEFAULT, DBPROPSET_COLUMN))
	{
		odtLog << "DBPROP_COL_DEFAULT is NOT SUPPORTED.\n";
		fSettable	= FALSE;
		fSupported	= FALSE;
	}
	else
	{
		if (!SettableProperty(DBPROP_COL_DEFAULT, DBPROPSET_COLUMN))
			fSettable = FALSE;
	}

	for (i=0; i<cColumnDesc; i++)
	{
		odtLog << GetColumnTypeName(&rgColumnDesc[i]);
		if (!CHECK(m_hr = m_pTable->CreateTable(0, 0), S_OK))
			continue;

		// try to add the column described by rgColumnDesc[i] to the table
		// and set it as a column with a default value
		VariantInit(&value);
		GetDefaultValue(&rgColumnDesc[i], &value, pTable);
		SetDefaultProperty(&rgColumnDesc[i].rgPropertySets, &rgColumnDesc[i].cPropertySets,
			&value, DBPROPOPTIONS_REQUIRED);	// might be not supported
		VariantClear(&value);
		//rgColumnDesc[i].ulColumnSize = 0;

		// since the property could be supported, writeable but unavailable for
		// certain data types, a return value cannot be enforced
		hr = AddColumnAndCheck(&m_pTable->GetTableID(), &rgColumnDesc[i], NULL);

		ulStatus = rgColumnDesc[i].rgPropertySets[0].rgProperties[0].dwStatus;
		if (S_OK == hr)
		{
			odtLog << "\t: column has been added with a DEFAULT VALUE\n";
			COMPARE(ulStatus, DBPROPSTATUS_OK);
			COMPARE(fSupported, TRUE);
		}
		else 
		{
			if (CHECK(hr, DB_E_ERRORSOCCURRED))
			{
				odtLog << "\t: column was added WITHOUT default value\n";
				if (!fSupported)
					COMPARE(ulStatus, DBPROPSTATUS_NOTSUPPORTED);
				// property could be settable but failing for this data type
				else if (fSettable)
					COMPARE(ulStatus, DBPROPSTATUS_BADVALUE);
				else
					COMPARE(ulStatus, DBPROPSTATUS_NOTSETTABLE);
			}
			else
			{
				odtLog << "\tERROR: column was NOT added\n";
			}
		}
		CHECK(m_pTable->DropTable(), S_OK);
		// the vt type of the default property could cause problems in VariantClear
		// call PrepareVariantToClear to check and fix
		FreeProperties( &rgColumnDesc[i].cPropertySets, &rgColumnDesc[i].rgPropertySets);
	}
	ReleaseColumnDesc(rgColumnDesc, cColumnDesc);
	delete pTable;
	TRETURN
}
// }}


// {{ TCW_VAR_PROTOTYPE(29)
//*-----------------------------------------------------------------------
// @mfunc DBPROP_COL_DESCRIPTION
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCAddColumn::Variation_29()
{
	TBEGIN
	DBORDINAL		i;
	WCHAR			*pwszName		= NULL;
	HRESULT			hr;
	BSTR			pwszDescription = NULL;
	DBCOLUMNDESC	*rgColumnDesc	= NULL;
	DBORDINAL		cColumnDesc		= 0;
	HRESULT			hExpRes			= S_OK;
	BOOL			fSettable		= TRUE;
	BOOL			fSupported		= TRUE;
	ULONG			ulStatus,
					cPropSet,
					cProp;

	if (!SupportedProperty(DBPROP_COL_DESCRIPTION, DBPROPSET_COLUMN))
	{
		odtLog << "DBPROP_COL_DESCRIPTION is NOT SUPPORTED.\n";
		hExpRes		= DB_S_ERRORSOCCURRED;
		fSettable	= FALSE;
		fSupported	= FALSE;
	}
	else
	{
		if (!SettableProperty(DBPROP_COL_DESCRIPTION, DBPROPSET_COLUMN))
		{
			fSettable = FALSE;
			odtLog << "Implementing the desricption property as readonly is strange. Please reconsider!\n";
		}
	}

	DuplicateColumnDesc(m_rgColumnDesc, m_cColumnDesc, &rgColumnDesc);
	cColumnDesc = m_cColumnDesc;
	ReleaseAllColumnPropSets(rgColumnDesc, cColumnDesc);
	m_pTable->SetBuildColumnDesc(FALSE);
	//SetZeroColSize(rgColumnDesc, cColumnDesc);
	pwszName = rgColumnDesc[0].dbcid.uName.pwszName;
	m_pTable->SetColumnDesc(rgColumnDesc, 1);
	pwszDescription = SysAllocString(L"ColumnDescription");

	for (i=0; i<cColumnDesc; i++)
	{
		odtLog << "column of type " << rgColumnDesc[i].pwszTypeName;

		rgColumnDesc[0].dbcid.uName.pwszName = L"First_column";
		if (!CHECK(m_hr = m_pTable->CreateTable(0, 0), S_OK))
		{
			if (SUCCEEDED(m_hr))
				CHECK(m_pTable->DropTable(), S_OK);
			continue;
		}

		rgColumnDesc[0].dbcid.uName.pwszName = pwszName;

		// try to add the column described by rgColumnDesc[i] to the table
		SetProperty(&rgColumnDesc[i].rgPropertySets, &rgColumnDesc[i].cPropertySets, 
			DBPROP_COL_DESCRIPTION, DBTYPE_BSTR, (LPVOID)pwszDescription, DBPROPOPTIONS_OPTIONAL,
			DB_NULLID, DBPROPSET_COLUMN, &cPropSet, &cProp);
		hr = AddColumnAndCheck(&m_pTable->GetTableID(), &rgColumnDesc[i], NULL);
				
		if (!fSupported)
			CHECK(hr, DB_S_ERRORSOCCURRED);
		else if (fSettable)
			CHECK(hr, S_OK);
		else if (S_OK != hr)
			CHECK(hr, DB_S_ERRORSOCCURRED);

		if (SUCCEEDED(hr))
			odtLog << ((DB_S_ERRORSOCCURRED == hr) ? ": could not add a description\n" : 
					": description has been added\n");

		ulStatus = rgColumnDesc[i].rgPropertySets[cPropSet].rgProperties[cProp].dwStatus; 
		if (!fSupported)
			COMPARE(ulStatus, DBPROPSTATUS_NOTSUPPORTED);
		else if (fSettable)
			COMPARE(ulStatus, DBPROPSTATUS_OK);
		else
			COMPARE(ulStatus, DBPROPSTATUS_BADVALUE);

		CHECK(m_pTable->DropTable(), S_OK);
		ReleaseAllColumnPropSets(&rgColumnDesc[i], 1);
	}

	SysFreeString(pwszDescription);
	rgColumnDesc[0].dbcid.uName.pwszName = pwszName;
	m_pTable->SetNoOfColumnDesc(cColumnDesc);
	TRETURN
}
// }}


// {{ TCW_VAR_PROTOTYPE(30)
//*-----------------------------------------------------------------------
// @mfunc DBPROP_COL_FIXEDLENGTH
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCAddColumn::Variation_30()
{
	TBEGIN
	HRESULT			hr;
	DBCOLUMNDESC	*pColumnDesc = NULL;
	BOOL			fFixedLength;
	DBORDINAL		i;
	CCol			col;
	DBCOLUMNDESC	*rgColumnDesc	= NULL;
	DBORDINAL		cColumnDesc		= 0;
	BOOL			fSettable = TRUE;
	BOOL			fSupported = TRUE;
	ULONG			ulStatus,
					cPropSet,
					cProp;

	if (!SupportedProperty(DBPROP_COL_FIXEDLENGTH, DBPROPSET_COLUMN))
	{
		odtLog << "DBPROP_COL_FIXEDLENGTH is NOT SUPPORTED\n";
		fSettable	= FALSE;
		fSupported	= FALSE;
	}
	else
	{
		if (!SettableProperty(DBPROP_COL_FIXEDLENGTH, DBPROPSET_COLUMN))
			fSettable = FALSE;
	}

	DuplicateColumnDesc(m_rgColumnDesc, m_cColumnDesc, &rgColumnDesc);
	cColumnDesc = m_cColumnDesc;
	ReleaseAllColumnPropSets(rgColumnDesc, cColumnDesc);
	m_pTable->SetBuildColumnDesc(FALSE);
	DuplicateColumnDesc(&rgColumnDesc[0], 1, &pColumnDesc);
	SetMaximumColSize(rgColumnDesc, cColumnDesc);
	PROVIDER_FREE(pColumnDesc->dbcid.uName.pwszName)
	pColumnDesc->dbcid.uName.pwszName = wcsDuplicate(L"First_column");
	m_pTable->SetColumnDesc(pColumnDesc, 1);

	for (i=0; i<cColumnDesc; i++)
	{
		if (	DBTYPE_STR != rgColumnDesc[i].wType
			&&	DBTYPE_WSTR != rgColumnDesc[i].wType
			&&	DBTYPE_BYTES != rgColumnDesc[i].wType)
			continue;

		col = GetType(GetColumnTypeName(&rgColumnDesc[i]), rgColumnDesc[i].wType);
		// just not yet implemented
		// pending for all providers to adjust the provider types schema rowset
		fFixedLength = col.GetIsFixedLength();
		if (fFixedLength)
			odtLog << GetColumnTypeName(&rgColumnDesc[i]) <<" is fixed length\n";
		else
			odtLog << GetColumnTypeName(&rgColumnDesc[i]) <<" is variable length\n";

		if (!CHECK(m_pTable->CreateTable(0, 0), S_OK))
			continue;

		// try to add the column described by rgColumnDesc[i] to the table
		// and set it as a fixed length column
		odtLog << "\ttry to add a fixed length column: ";
		SetProperty(&rgColumnDesc[i].rgPropertySets, &rgColumnDesc[i].cPropertySets,
			DBPROP_COL_FIXEDLENGTH, VT_BOOL, (LPVOID)VARIANT_TRUE, DBPROPOPTIONS_REQUIRED,
			DB_NULLID, DBPROPSET_COLUMN, &cPropSet, &cProp);
		rgColumnDesc[i].bScale = 0;

		hr = AddColumnAndCheck(&m_pTable->GetTableID(), &rgColumnDesc[i], NULL);

		ulStatus = rgColumnDesc[i].rgPropertySets[cPropSet].rgProperties[cProp].dwStatus;
		if (S_OK == hr)
			COMPARE(ulStatus, DBPROPSTATUS_OK);
		else 
		{
			CHECK(hr, DB_E_ERRORSOCCURRED);
			
			if (!fSupported)
				COMPARE(ulStatus, DBPROPSTATUS_NOTSUPPORTED);
			else if (fSettable)
				COMPARE(ulStatus, DBPROPSTATUS_BADVALUE);
			else if (!fSettable)
				COMPARE(ulStatus, DBPROPSTATUS_NOTSETTABLE);
		}

		odtLog << ((S_OK == hr)? "ok\n" : "failed\n");
		ReleaseAllColumnPropSets(&rgColumnDesc[i], 1);
		CHECK(m_pTable->DropTable(), S_OK);
		
		if (!CHECK(m_pTable->CreateTable(0, 0), S_OK))
			continue;

		// try to add the column described by rgColumnDesc[i] to the table
		// and set it as a variable_length
		odtLog << "\ttry to add a variable length column: ";
		SetProperty(&rgColumnDesc[i].rgPropertySets, &rgColumnDesc[i].cPropertySets,
			DBPROP_COL_FIXEDLENGTH, VT_BOOL, (LPVOID)VARIANT_FALSE, DBPROPOPTIONS_REQUIRED,
			DB_NULLID, DBPROPSET_COLUMN, &cPropSet, &cProp);
		rgColumnDesc[i].bScale = 0;
		
		hr = AddColumnAndCheck(&m_pTable->GetTableID(), 
				&rgColumnDesc[i], NULL);

		ulStatus = rgColumnDesc[i].rgPropertySets[cPropSet].rgProperties[cProp].dwStatus;
		if (S_OK == hr)
			COMPARE(ulStatus, DBPROPSTATUS_OK);
		else
		{
			CHECK(hr, DB_E_ERRORSOCCURRED);
			if (!fSupported)
				COMPARE(ulStatus, DBPROPSTATUS_NOTSUPPORTED);
			else if (fSettable)
				COMPARE(ulStatus, DBPROPSTATUS_BADVALUE);
			else 
				COMPARE(ulStatus, DBPROPSTATUS_NOTSETTABLE);
		}

		odtLog << ((S_OK == hr)? "ok\n" : "failed\n");

		ReleaseAllColumnPropSets(&rgColumnDesc[i], 1);
		CHECK(m_pTable->DropTable(), S_OK);
	}

	ReleaseColumnDesc(rgColumnDesc, cColumnDesc);
	TRETURN
}
// }}


// {{ TCW_VAR_PROTOTYPE(31)
//*-----------------------------------------------------------------------
// @mfunc DBPROP_COL_NULLABLE
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCAddColumn::Variation_31()
{
	TBEGIN
	DBCOLUMNDESC			*pColumnDesc = NULL;
	BOOL					fNotNullable, fNullable;
	DBORDINAL				i;
	VARIANT					value, defval;
	CCol					col;
	HRESULT					hr;
	DBPROP					*pProp			= NULL;
	DBPROP					*pPropDefault	= NULL;
	DBCOLUMNDESC			*rgColumnDesc	= NULL;
	DBORDINAL				cColumnDesc		= 0;
	CTable					*pTable = new CTable(m_pThisTestModule->m_pIUnknown2, (LPWSTR)gwszModuleName);
	CList<WCHAR *,WCHAR *>	NativeTypesList;
	CList<DBTYPE,DBTYPE>	ProviderTypesList;
	BOOL					fSettable = TRUE;
	BOOL					fSupported = TRUE;
	ULONG					ulStatus,
							cPropSet,
							cProp;

	if (!SupportedProperty(DBPROP_COL_NULLABLE, DBPROPSET_COLUMN))
	{
		odtLog << "DBPROP_COL_NULLABLE is NOT SUPPORTED\n";
		fSettable	= FALSE;
		fSupported	= FALSE;
	}
	else
	{
		if (!SettableProperty(DBPROP_COL_NULLABLE, DBPROPSET_COLUMN))
			fSettable = FALSE;
	}

	pTable->CreateTypeColInfo(NativeTypesList, ProviderTypesList);
	DuplicateColumnDesc(m_rgColumnDesc, m_cColumnDesc, &rgColumnDesc);
	cColumnDesc = m_cColumnDesc;
	ReleaseAllColumnPropSets(rgColumnDesc, cColumnDesc);
	m_pTable->SetBuildColumnDesc(FALSE);
	DuplicateColumnDesc(&rgColumnDesc[0], 1, &pColumnDesc);
	PROVIDER_FREE(pColumnDesc->dbcid.uName.pwszName)
	pColumnDesc->dbcid.uName.pwszName = wcsDuplicate(L"First_column");
	m_pTable->SetColumnDesc(pColumnDesc, 1);
	value.vt	= VT_BOOL;

	for (i=0; i<cColumnDesc; i++)
	{
		col = GetType(GetColumnTypeName(&rgColumnDesc[i]), rgColumnDesc[i].wType);
		fNotNullable	= FALSE;
		fNullable		= FALSE;
		switch (col.GetNullable())
		{
			case 1:
				odtLog << GetColumnTypeName(&rgColumnDesc[i]) <<" is nullable: \n";
				fNullable = TRUE;
				break;
			case 0:
				odtLog << GetColumnTypeName(&rgColumnDesc[i]) <<" is not nullable: \n";
				fNotNullable = TRUE;
				break;
			default:
				odtLog << GetColumnTypeName(&rgColumnDesc[i]) <<": nullable/not nullable information was not found\n";
				break;
		}

		if (!CHECK(m_hr = m_pTable->CreateTable(0, 0), S_OK))
			continue;

		// try to add the column described by rgColumnDesc[i] to the table
		// and set it as a nullable one
		//odtLog << "try to add a nullable column\n";
		SetProperty(&rgColumnDesc[i].rgPropertySets, &rgColumnDesc[i].cPropertySets,
			DBPROP_COL_NULLABLE, VT_BOOL, (LPVOID)VARIANT_TRUE, DBPROPOPTIONS_REQUIRED, DB_NULLID,
			DBPROPSET_COLUMN, &cPropSet, &cProp);
		rgColumnDesc[i].bScale = 0;
		
		// try to add a column but do not require the seccess of the operation
		// though the column is declared nullable, adding a column could be unimplemented in the provider
		hr = AddColumnAndCheck(&m_pTable->GetTableID(), &rgColumnDesc[i], NULL);

		if (fNullable)
			CHECK(hr, S_OK);

		ulStatus = rgColumnDesc[i].rgPropertySets[cPropSet].rgProperties[cProp].dwStatus;
		
		if (S_OK == hr)
			COMPARE(ulStatus, DBPROPSTATUS_OK);
		else
		{
			CHECK(hr, DB_E_ERRORSOCCURRED);
			if (!fSupported)
				COMPARE(ulStatus, DBPROPSTATUS_NOTSUPPORTED);
			else if (fSettable)
				COMPARE(ulStatus, DBPROPSTATUS_BADVALUE);
			else
				COMPARE(ulStatus, DBPROPSTATUS_NOTSETTABLE);
		}

		ReleaseAllColumnPropSets(&rgColumnDesc[i], 1);
		CHECK(m_pTable->DropTable(), S_OK);
		
		if (!CHECK(m_hr = m_pTable->CreateTable(0, 0), S_OK))
			continue;

		// try to add the column described by rgColumnDesc[i] to the table
		// and set it as a variable_length
		//odtLog << "try to add a non nullable column\n";
		SetProperty(&rgColumnDesc[i].rgPropertySets, &rgColumnDesc[i].cPropertySets,
			DBPROP_COL_NULLABLE, VT_BOOL, (LPVOID)VARIANT_FALSE, DBPROPOPTIONS_REQUIRED,
			DB_NULLID, DBPROPSET_COLUMN, &cPropSet, &cProp);
		rgColumnDesc[i].bScale = 0;

		// Commenting out the default value
		VariantInit(&defval);
		GetDefaultValue(&rgColumnDesc[i], &defval, pTable);
		if (SettableProperty(DBPROP_COL_DEFAULT, DBPROPSET_COLUMN))
			SetDefaultProperty(&rgColumnDesc[i].rgPropertySets, &rgColumnDesc[i].cPropertySets,
				&defval, DBPROPOPTIONS_REQUIRED);	// might be not supported
		VariantClear(&defval);
		
		// it is not necessary that a not nullable column be added
		hr = AddColumnAndCheck(&m_pTable->GetTableID(), &rgColumnDesc[i], NULL);

		ulStatus = rgColumnDesc[i].rgPropertySets[cPropSet].rgProperties[cProp].dwStatus;
		if (S_OK == hr)
			COMPARE(ulStatus, DBPROPSTATUS_OK);
		else
		{
			CHECK(hr, DB_E_ERRORSOCCURRED);
			if (DBPROPSTATUS_OK == rgColumnDesc[i].rgPropertySets[cPropSet].rgProperties[cProp + 1].dwStatus)
			{
				if (!fSupported)
					COMPARE(ulStatus, DBPROPSTATUS_NOTSUPPORTED);
				else if (fSettable)
					COMPARE(ulStatus, DBPROPSTATUS_BADVALUE);
				else
					COMPARE(ulStatus, DBPROPSTATUS_NOTSETTABLE);
			}
		}

		ReleaseAllColumnPropSets(&rgColumnDesc[i], 1);
		CHECK(m_pTable->DropTable(), S_OK);
	}
	ReleaseColumnDesc(rgColumnDesc, cColumnDesc);
	delete pTable;
	TRETURN
}
// }}


// {{ TCW_VAR_PROTOTYPE(32)
//*-----------------------------------------------------------------------
// @mfunc DBPROP_PRIMARYKEY
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCAddColumn::Variation_32()
{
	TBEGIN
	DBCOLUMNDESC			*pColumnDesc = NULL;
	DBORDINAL				i;
	VARIANT					value;
	CCol					col;
	HRESULT					hr;
	DBCOLUMNDESC			*rgColumnDesc	= NULL;
	DBORDINAL				cColumnDesc		= 0;
	CTable					*pTable = new CTable(m_pThisTestModule->m_pIUnknown2, (LPWSTR)gwszModuleName);
	CList<WCHAR *,WCHAR *>	NativeTypesList;
	CList<DBTYPE,DBTYPE>	ProviderTypesList;
	BOOL					fSettable;
	BOOL					fDefaultIsSettable = SettableProperty(DBPROP_COL_DEFAULT, DBPROPSET_COLUMN);
	ULONG					cPropSet1, cProp1, cPropSet2, cProp2;
	DBPROPSTATUS			dwStatus1, dwStatus2;

	fSettable = SettableProperty(DBPROP_COL_PRIMARYKEY, DBPROPSET_COLUMN);

	pTable->CreateTypeColInfo(NativeTypesList, ProviderTypesList);
	DuplicateColumnDesc(m_rgColumnDesc, m_cColumnDesc, &rgColumnDesc);
	cColumnDesc = m_cColumnDesc;
	ReleaseAllColumnPropSets(rgColumnDesc, cColumnDesc);
	m_pTable->SetBuildColumnDesc(FALSE);
	DuplicateColumnDesc(&rgColumnDesc[0], 1, &pColumnDesc);
	// this is to prevent SQL Server limiting the size of
	// the index it creates for primary key or unique columns
	SetZeroColSize(rgColumnDesc, cColumnDesc);
	PROVIDER_FREE(pColumnDesc->dbcid.uName.pwszName)
	pColumnDesc->dbcid.uName.pwszName = wcsDuplicate(L"First_column");
	m_pTable->SetColumnDesc(pColumnDesc, 1);

	for (i=0; i<cColumnDesc; i++)
	{
		col = GetType(GetColumnTypeName(&rgColumnDesc[i]), rgColumnDesc[i].wType);
		odtLog <<  GetColumnTypeName(&rgColumnDesc[i]) << "\n";
		if (!CHECK(m_hr = m_pTable->CreateTable(0, 0), S_OK))
			continue;

		// try to add the column described by rgColumnDesc[i] to the table
		// and set it as a PRIMARY KEY  column
		SetProperty(&rgColumnDesc[i].rgPropertySets, &rgColumnDesc[i].cPropertySets,
			DBPROP_COL_PRIMARYKEY, VT_BOOL, (LPVOID)VARIANT_TRUE, DBPROPOPTIONS_OPTIONAL, DB_NULLID,
			DBPROPSET_COLUMN, &cPropSet1, &cProp1);
		if (fDefaultIsSettable)
		{
			VariantInit(&value);
			GetDefaultValue(&rgColumnDesc[i], &value, pTable);
			SetDefaultProperty(&rgColumnDesc[i].rgPropertySets, &rgColumnDesc[i].cPropertySets,
				&value, DBPROPOPTIONS_OPTIONAL, DB_NULLID, DBPROPSET_COLUMN, &cPropSet2, &cProp2);	// might be not supported
			VariantClear(&value);
		}
		rgColumnDesc[i].bScale = 0;
		
		hr = AddColumnAndCheck(&m_pTable->GetTableID(), &rgColumnDesc[i], NULL);
		dwStatus1 = rgColumnDesc[i].rgPropertySets[cPropSet1].rgProperties[cProp1].dwStatus;
		dwStatus2 = rgColumnDesc[i].rgPropertySets[cPropSet2].rgProperties[cProp2].dwStatus;

		if (hr != S_OK)
		{
			CHECK(hr, DB_S_ERRORSOCCURRED);
			COMPARE(dwStatus1==DBPROPSTATUS_NOTSET || dwStatus2==DBPROPSTATUS_NOTSET, TRUE);
			if (hr==DB_S_ERRORSOCCURRED && dwStatus1==S_OK)
				odtLog << "\tcolumn added as a primary key\n";
			if (hr==DB_S_ERRORSOCCURRED && dwStatus2==S_OK)
				odtLog << "\tcolumn added with the default\n";
		}
		else
		{
			COMPARE(fSettable, TRUE);
			odtLog << "\tcolumn added as a primary key\n";
			COMPARE(dwStatus1, DBPROPSTATUS_OK);
			COMPARE(dwStatus2, DBPROPSTATUS_OK);
		}
		
		ReleaseAllColumnPropSets(&rgColumnDesc[i], 1);
		CHECK(m_pTable->DropTable(), S_OK);
		
		if (!CHECK(m_hr = m_pTable->CreateTable(0, 0), S_OK))
			continue;

		// try to add the column described by rgColumnDesc[i] to the table
		// and set it as a PRIMARY KEY column
		SetProperty(&rgColumnDesc[i].rgPropertySets, &rgColumnDesc[i].cPropertySets,
			DBPROP_COL_PRIMARYKEY, VT_BOOL, (LPVOID)VARIANT_FALSE, DBPROPOPTIONS_OPTIONAL, DB_NULLID,
			DBPROPSET_COLUMN, &cPropSet1, &cProp1);
		rgColumnDesc[i].bScale = 0;
		
		hr = AddColumnAndCheck(&m_pTable->GetTableID(), &rgColumnDesc[i], NULL);
		dwStatus1 = rgColumnDesc[i].rgPropertySets[cPropSet1].rgProperties[cProp1].dwStatus;
		if (hr != S_OK)
		{
			COMPARE(fSettable, FALSE);
			CHECK(hr, DB_S_ERRORSOCCURRED);
			COMPARE(dwStatus1==DBPROPSTATUS_NOTSET, TRUE);
		}
		else
		{
			COMPARE(fSettable, TRUE);
			odtLog << "\tcolumn was added with primary property off\n";
			COMPARE(dwStatus1, DBPROPSTATUS_OK);
		}
		ReleaseAllColumnPropSets(&rgColumnDesc[i], 1);
		CHECK(m_pTable->DropTable(), S_OK);
	}

	ReleaseColumnDesc(rgColumnDesc, cColumnDesc);
	SAFE_DELETE(pTable);
	TRETURN
}
// }}


// {{ TCW_VAR_PROTOTYPE(33)
//*-----------------------------------------------------------------------
// @mfunc DBPROP_COL_UNIQUE
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCAddColumn::Variation_33()
{
	TBEGIN
	DBCOLUMNDESC	*pColumnDesc = NULL;
	DBORDINAL		i;
	CCol			col;
	HRESULT			hr;
	DBPROP			*pProp;
	DBCOLUMNDESC	*rgColumnDesc	= NULL;
	DBORDINAL		cColumnDesc		= 0;
	BOOL			fSettable		= FALSE;
	BOOL			fSupported		= FALSE;

	DuplicateColumnDesc(m_rgColumnDesc, m_cColumnDesc, &rgColumnDesc);
	cColumnDesc = m_cColumnDesc;
	ReleaseAllColumnPropSets(rgColumnDesc, cColumnDesc);
	m_pTable->SetBuildColumnDesc(FALSE);
	DuplicateColumnDesc(&rgColumnDesc[0], 1, &pColumnDesc);
	// this is to prevent SQL Server limiting the size of
	// the index it creates for primary key or unique columns
	SetZeroColSize(rgColumnDesc, cColumnDesc);
	PROVIDER_FREE(pColumnDesc->dbcid.uName.pwszName)
	pColumnDesc->dbcid.uName.pwszName = wcsDuplicate(L"First_column");
	m_pTable->SetColumnDesc(pColumnDesc, 1);
	
	fSupported	= SupportedProperty(DBPROP_COL_UNIQUE, DBPROPSET_COLUMN);
	fSettable	= SettableProperty(DBPROP_COL_UNIQUE, DBPROPSET_COLUMN);

	for (i=0; i<cColumnDesc; i++)
	{
		col = GetType(GetColumnTypeName(&rgColumnDesc[i]), rgColumnDesc[i].wType);
		if (!CHECK(m_hr = m_pTable->CreateTable(0, 0), S_OK))
			continue;

		// try to add the column described by rgColumnDesc[i] to the table
		// and set it as a UNIQUE column
		SetProperty(&rgColumnDesc[i].rgPropertySets, &rgColumnDesc[i].cPropertySets,
			DBPROP_COL_UNIQUE, VT_BOOL, (LPVOID)VARIANT_TRUE, DBPROPOPTIONS_REQUIRED);
		rgColumnDesc[i].bScale = 0;
		odtLog << GetColumnTypeName(&rgColumnDesc[i]) << "\n";
		odtLog << "\ttry to add a unique column; \n";

		hr = AddColumnAndCheck(&m_pTable->GetTableID(), &rgColumnDesc[i], NULL);

		FindProperty(
					DBPROP_COL_UNIQUE,
					DBPROPSET_COLUMN,
					rgColumnDesc[i].cPropertySets,
					rgColumnDesc[i].rgPropertySets, 
					&pProp);
		
		if (S_OK == hr)
		{
			COMPARE(pProp->dwStatus, DBPROPSTATUS_OK);
			COMPARE(fSupported, TRUE);
		}
		else
		{
			CHECK(hr, DB_E_ERRORSOCCURRED);
		
			if (!fSupported)
				COMPARE(pProp->dwStatus, DBPROPSTATUS_NOTSUPPORTED);
			else if (fSettable)
				COMPARE(pProp->dwStatus, DBPROPSTATUS_BADVALUE);
			else
				COMPARE(pProp->dwStatus, DBPROPSTATUS_NOTSETTABLE);
		}

		ReleaseAllColumnPropSets(&rgColumnDesc[i], 1);
		CHECK(m_pTable->DropTable(), S_OK);
		
		if (!CHECK(m_pTable->CreateTable(0, 0), S_OK))
			continue;

		// try to add the column described by rgColumnDesc[i] to the table
		// and set it as a unique column
		SetProperty(&rgColumnDesc[i].rgPropertySets, &rgColumnDesc[i].cPropertySets,
			DBPROP_COL_UNIQUE, VT_BOOL, (LPVOID)VARIANT_FALSE, DBPROPOPTIONS_REQUIRED);
		rgColumnDesc[i].bScale = 0;
		odtLog << "\ttry to add a not unique column; \n";

		hr = AddColumnAndCheck(&m_pTable->GetTableID(), &rgColumnDesc[i], NULL);

		FindProperty(
						DBPROP_COL_UNIQUE,
						DBPROPSET_COLUMN,
						rgColumnDesc[i].cPropertySets,
						rgColumnDesc[i].rgPropertySets, 
						&pProp
					);
		
		if (S_OK == hr)
		{
			COMPARE(pProp->dwStatus, DBPROPSTATUS_OK);
			COMPARE(fSupported, TRUE);
		}
		else
		{
			CHECK(hr, DB_E_ERRORSOCCURRED);
		
			if (!fSupported)
				COMPARE(pProp->dwStatus, DBPROPSTATUS_NOTSUPPORTED);
			else if (fSettable)
				COMPARE(pProp->dwStatus, DBPROPSTATUS_BADVALUE);
			else
				COMPARE(pProp->dwStatus, DBPROPSTATUS_NOTSETTABLE);
		}
		ReleaseAllColumnPropSets(&rgColumnDesc[i], 1);
		CHECK(m_pTable->DropTable(), S_OK);
	}

	ReleaseColumnDesc(rgColumnDesc, cColumnDesc);
	TRETURN
}
// }}


// {{ TCW_VAR_PROTOTYPE(34)
//*-----------------------------------------------------------------------
// @mfunc Duplicate an existing column => DB_E_DUPLCATECOLUMNID
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCAddColumn::Variation_34()
{
	TBEGIN
	DBID			*pColumnID		= NULL;
	DBCOLUMNDESC	*rgColumnDesc	= NULL;
	DBORDINAL		cColumnDesc		= 0;

	DuplicateColumnDesc(m_rgColumnDesc, m_cColumnDesc, &rgColumnDesc);
	cColumnDesc = m_cColumnDesc;
	ReleaseAllColumnPropSets(rgColumnDesc, cColumnDesc);
	m_pTable->SetColumnDesc(rgColumnDesc, cColumnDesc);
	m_pTable->SetBuildColumnDesc(FALSE);

	TESTC_(m_pTable->CreateTable(0, 0), S_OK);

	// try to add a column to this maximum length name table
	TESTC_(AddColumnAndCheck(&m_pTable->GetTableID(), &rgColumnDesc[cColumnDesc-1], 
		&pColumnID),DB_E_DUPLICATECOLUMNID);

CLEANUP:
	CHECK(m_pTable->DropTable(), S_OK);
	ReleaseDBID(pColumnID);
	TRETURN
}
// }}


// {{ TCW_VAR_PROTOTYPE(35)
//*-----------------------------------------------------------------------
// @mfunc Abort retaining
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCAddColumn::Variation_35()
{
	TBEGIN
	ITransactionLocal	*pITransactionLocal = NULL;
	DBCOLUMNDESC		*newCD			= NULL;
	DBCOLUMNDESC		*oldCD			= NULL;
	DBORDINAL			newlen			= 0;
	DBORDINAL			oldlen			= 0;
	DBID				*pColumnID		= NULL;
	DBCOLUMNDESC		*rgColumnDesc	= NULL;
	DBORDINAL			cColumnDesc		= 0;
	VARIANT				vSupportedTxnDDL;
	BOOL				fTxnStarted		= FALSE;

	TESTC_PROVIDER(VerifyInterface(m_pITableDefinition, IID_ITransactionLocal, 
			SESSION_INTERFACE, (IUnknown**)&pITransactionLocal));

	VariantInit(&vSupportedTxnDDL);
	TESTC_PROVIDER(GetProperty(DBPROP_SUPPORTEDTXNDDL, DBPROPSET_DATASOURCEINFO, 
			g_pIDBInitialize, &vSupportedTxnDDL));
	
	TESTC(VT_I4 == vSupportedTxnDDL.vt);
	// what values should we accept?
	TESTC_PROVIDER(DBPROPVAL_TC_NONE != vSupportedTxnDDL.lVal);

	DuplicateColumnDesc(m_rgColumnDesc, m_cColumnDesc, &rgColumnDesc);
	cColumnDesc = m_cColumnDesc;
	ReleaseAllColumnPropSets(rgColumnDesc, cColumnDesc);
	m_pTable->SetBuildColumnDesc(FALSE);
	m_pTable->SetColumnDesc(rgColumnDesc, cColumnDesc);
		
	// create a table and populate it
	TESTC_(m_hr = m_pTable->CreateTable(0, 0), S_OK);

	GetColumnDescOnTable(&m_pTable->GetTableID(), &oldCD, &oldlen);

	// start the transaction
	TESTC_(StartTransaction(pITransactionLocal), S_OK);
	fTxnStarted = TRUE;

	// try to add a column to this maximum length name table
	if (rgColumnDesc[0].dbcid.uName.pwszName)
		PROVIDER_FREE(rgColumnDesc[0].dbcid.uName.pwszName);
	rgColumnDesc[0].dbcid.uName.pwszName = L"transacted_column";

	switch(vSupportedTxnDDL.lVal)
	{
		case DBPROPVAL_TC_DML:
			//check for XACT_E_XTIONEXISTS
			CHECK(m_hr = m_pITableDefinition->AddColumn(
				&m_pTable->GetTableID(), 
				&rgColumnDesc[0], 
				&pColumnID), XACT_E_XTIONEXISTS);
			break;

		case DBPROPVAL_TC_DDL_IGNORE:
			// the statement is not transacted
		case DBPROPVAL_TC_ALL:
		case DBPROPVAL_TC_DDL_COMMIT:
			CHECK(AddColumnAndCheck(&m_pTable->GetTableID(), 
				&rgColumnDesc[0], &pColumnID), S_OK);
			break;

		case DBPROPVAL_TC_DDL_LOCK:
			// error should be returned
			CHECK(m_pITableDefinition->AddColumn(
				&m_pTable->GetTableID(), 
				&rgColumnDesc[0], 
				&pColumnID), S_OK);
			break;
			
		default:
			TESTC(FALSE);
	}

	// abort retaining
	if (DBPROPVAL_TC_DDL_COMMIT != vSupportedTxnDDL.lVal)
	{
		CHECK(pITransactionLocal->Abort(NULL, TRUE, FALSE), S_OK);
		// check that it is retaining (another transaction is available)
		CHECK(m_hr = pITransactionLocal->Abort(NULL, FALSE, FALSE), S_OK);
	}

	GetColumnDescOnTable(&m_pTable->GetTableID(), &newCD, &newlen);
	if (	DBPROPVAL_TC_DDL_IGNORE == vSupportedTxnDDL.lVal
		||	DBPROPVAL_TC_DDL_COMMIT == vSupportedTxnDDL.lVal)
	{	// check column was added
		COMPARE(CheckColInfo(oldCD, oldlen, newCD, newlen, &rgColumnDesc[0]), TRUE);
	}
	else
	{	// check column was not added
		COMPARE(AreColEqual(oldCD, oldlen, newCD, newlen), TRUE);
	}
	ReleaseColumnDesc(newCD, newlen);
	newCD	= NULL;
	newlen	= 0;

CLEANUP:
	ReleaseColumnDesc(oldCD, oldlen);
	m_hr = m_pTable->DropTable();
	
	SAFE_RELEASE(pITransactionLocal);
	if (rgColumnDesc)
		rgColumnDesc[0].dbcid.uName.pwszName = NULL;
	ReleaseDBID(pColumnID);
	TRETURN
}
// }}


// {{ TCW_VAR_PROTOTYPE(36)
//*-----------------------------------------------------------------------
// @mfunc Abort without retaining
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCAddColumn::Variation_36()
{
	TBEGIN
	ITransactionLocal	*pITransactionLocal = NULL;
	DBCOLUMNDESC		*newCD			= NULL;
	DBCOLUMNDESC		*oldCD			= NULL;
	DBORDINAL			newlen			= 0;
	DBORDINAL			oldlen			= 0;
	DBID				*pColumnID		= NULL;
	DBCOLUMNDESC		*rgColumnDesc	= NULL;
	DBORDINAL			cColumnDesc		= 0;
	VARIANT				vSupportedTxnDDL;

	TESTC_PROVIDER(VerifyInterface(m_pITableDefinition, IID_ITransactionLocal, 
			SESSION_INTERFACE, (IUnknown**)&pITransactionLocal));

	VariantInit(&vSupportedTxnDDL);
	TESTC_PROVIDER(GetProperty(DBPROP_SUPPORTEDTXNDDL, DBPROPSET_DATASOURCEINFO, 
			g_pIDBInitialize, &vSupportedTxnDDL));
	
	TESTC(VT_I4 == vSupportedTxnDDL.vt);
	// what values should we accept?
	TESTC_PROVIDER(DBPROPVAL_TC_NONE != vSupportedTxnDDL.lVal);

	DuplicateColumnDesc(m_rgColumnDesc, m_cColumnDesc, &rgColumnDesc);
	cColumnDesc = m_cColumnDesc;
	ReleaseAllColumnPropSets(rgColumnDesc, cColumnDesc);
	m_pTable->SetBuildColumnDesc(FALSE);
	m_pTable->SetColumnDesc(rgColumnDesc, cColumnDesc);
		
	// create a table and populate it
	TESTC_(m_hr = m_pTable->CreateTable(0, 0), S_OK);

	GetColumnDescOnTable(&m_pTable->GetTableID(), &oldCD, &oldlen);

	// start the transaction
	TESTC_(StartTransaction(pITransactionLocal), S_OK);

	// try to add a column to this maximum length name table
	if (rgColumnDesc[0].dbcid.uName.pwszName)
		PROVIDER_FREE(rgColumnDesc[0].dbcid.uName.pwszName);
	rgColumnDesc[0].dbcid.uName.pwszName = L"transacted_column";

	switch(vSupportedTxnDDL.lVal)
	{
		case DBPROPVAL_TC_DML:
			//check for XACT_E_XTIONEXISTS
			CHECK(m_hr = m_pITableDefinition->AddColumn(
				&m_pTable->GetTableID(), 
				&rgColumnDesc[0], 
				&pColumnID), XACT_E_XTIONEXISTS);
			break;

		case DBPROPVAL_TC_DDL_IGNORE:
			// the statement is not transacted
		case DBPROPVAL_TC_ALL:
		case DBPROPVAL_TC_DDL_COMMIT:
			CHECK(AddColumnAndCheck(&m_pTable->GetTableID(), 
				&rgColumnDesc[0], &pColumnID), S_OK);
			break;

		case DBPROPVAL_TC_DDL_LOCK:
			// error should be returned
			CHECK(m_pITableDefinition->AddColumn(
				&m_pTable->GetTableID(), 
				&rgColumnDesc[0], 
				&pColumnID), S_OK);
			break;
			
		default:
			TESTC(FALSE);
	}

	// abort without retaining
	if (DBPROPVAL_TC_DDL_COMMIT != vSupportedTxnDDL.lVal)
	{
		// abort without retaining
		CHECK(m_hr = pITransactionLocal->Abort(NULL, FALSE, FALSE), S_OK);
		CHECK(pITransactionLocal->Abort(NULL, FALSE, FALSE), 
			SUCCEEDED(m_hr)? XACT_E_NOTRANSACTION : S_OK);
	}
	// check column was not added
	GetColumnDescOnTable(&m_pTable->GetTableID(), &newCD, &newlen);
	if (	DBPROPVAL_TC_DDL_IGNORE == vSupportedTxnDDL.lVal
		||	DBPROPVAL_TC_DDL_COMMIT == vSupportedTxnDDL.lVal)
	{	// check column was added
		COMPARE(CheckColInfo(oldCD, oldlen, newCD, newlen, &rgColumnDesc[0]), TRUE);
	}
	else
	{	// check column was not added
		COMPARE(AreColEqual(oldCD, oldlen, newCD, newlen), TRUE);
	}
	ReleaseColumnDesc(newCD, newlen);
	newCD	= NULL;
	newlen	= 0;

CLEANUP:
	ReleaseColumnDesc(oldCD, oldlen);
	m_hr = m_pTable->DropTable();
	
	SAFE_RELEASE(pITransactionLocal);
	if (rgColumnDesc)
		rgColumnDesc[0].dbcid.uName.pwszName = NULL;
	ReleaseDBID(pColumnID);
	TRETURN
}
// }}


// {{ TCW_VAR_PROTOTYPE(37)
//*-----------------------------------------------------------------------
// @mfunc Commit with retain
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCAddColumn::Variation_37()
{
	TBEGIN
	ITransactionLocal	*pITransactionLocal		= NULL;
	DBCOLUMNDESC		*newCD = NULL, *oldCD	= NULL;
	DBORDINAL			newlen = 0, oldlen		= 0;
	DBID				*pColumnID				= NULL;
	DBCOLUMNDESC		*rgColumnDesc			= NULL;
	DBORDINAL			cColumnDesc				= 0;
	VARIANT				vSupportedTxnDDL;

	TESTC_PROVIDER(VerifyInterface(m_pITableDefinition, IID_ITransactionLocal, 
			SESSION_INTERFACE, (IUnknown**)&pITransactionLocal));

	VariantInit(&vSupportedTxnDDL);
	TESTC_PROVIDER(GetProperty(DBPROP_SUPPORTEDTXNDDL, DBPROPSET_DATASOURCEINFO, 
			g_pIDBInitialize, &vSupportedTxnDDL));
	
	TESTC(VT_I4 == vSupportedTxnDDL.vt);
	// what values should we accept?
	TESTC_PROVIDER(DBPROPVAL_TC_NONE != vSupportedTxnDDL.lVal);

	DuplicateColumnDesc(m_rgColumnDesc, m_cColumnDesc, &rgColumnDesc);
	cColumnDesc = m_cColumnDesc;
	ReleaseAllColumnPropSets(rgColumnDesc, cColumnDesc);
	m_pTable->SetBuildColumnDesc(FALSE);
	m_pTable->SetColumnDesc(rgColumnDesc, cColumnDesc);
	
	// create a table and populate it
	TESTC_(m_hr = m_pTable->CreateTable(0, 0), S_OK);

	GetColumnDescOnTable(&m_pTable->GetTableID(), &oldCD, &oldlen);

	// start the transaction
	TESTC_(StartTransaction(pITransactionLocal), S_OK);

	// try to add a column to this maximum length name table
	if (rgColumnDesc[0].dbcid.uName.pwszName)
		PROVIDER_FREE(rgColumnDesc[0].dbcid.uName.pwszName);

	rgColumnDesc[0].dbcid.uName.pwszName = wcsDuplicate(L"transacted_column");

	switch(vSupportedTxnDDL.lVal)
	{
		case DBPROPVAL_TC_DML:
			//check for XACT_E_XTIONEXISTS
			CHECK(m_hr = m_pITableDefinition->AddColumn(
				&m_pTable->GetTableID(), 
				&rgColumnDesc[0], 
				&pColumnID), XACT_E_XTIONEXISTS);
			break;

		case DBPROPVAL_TC_DDL_IGNORE:
			// the statement is not transacted
		case DBPROPVAL_TC_ALL:
		case DBPROPVAL_TC_DDL_COMMIT:
			CHECK(AddColumnAndCheck(&m_pTable->GetTableID(), 
				&rgColumnDesc[0], &pColumnID), S_OK);
			break;

		case DBPROPVAL_TC_DDL_LOCK:
			// error should be returned
			CHECK(m_pITableDefinition->AddColumn(
				&m_pTable->GetTableID(), 
				&rgColumnDesc[0], 
				&pColumnID), S_OK);
			break;
			
		default:
			TESTC(FALSE);
	}
	
	// commit with retaining
	if (DBPROPVAL_TC_DDL_COMMIT != vSupportedTxnDDL.lVal)
	{
		CHECK(pITransactionLocal->Commit(TRUE, 0, 0), S_OK); //XACTTC_SYNC, 0), S_OK))
		//check the commit with retaining 
		CHECK(m_hr = pITransactionLocal->Abort(NULL, FALSE, FALSE), S_OK);
	}

	GetColumnDescOnTable(&m_pTable->GetTableID(), &newCD, &newlen);
	if (DBPROPVAL_TC_DML == vSupportedTxnDDL.lVal)
	{	// check column was not added
		COMPARE(AreColEqual(oldCD, oldlen, newCD, newlen), TRUE);
	}
	else
	{	// check column was added
		COMPARE(CheckColInfo(oldCD, oldlen, newCD, newlen, &rgColumnDesc[0]), TRUE);
	}
	ReleaseColumnDesc(newCD, newlen);
	newCD	= NULL;
	newlen	= 0;

CLEANUP:
	if (rgColumnDesc)
		rgColumnDesc[0].dbcid.uName.pwszName = NULL;
	SAFE_RELEASE(pITransactionLocal);
	ReleaseColumnDesc(oldCD, oldlen);
	m_hr = m_pTable->DropTable();
	ReleaseDBID(pColumnID);
	TRETURN
}
// }}


// {{ TCW_VAR_PROTOTYPE(38)
//*-----------------------------------------------------------------------
// @mfunc Commit without retain
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCAddColumn::Variation_38()
{
	TBEGIN
	ITransactionLocal	*pITransactionLocal		= NULL;
	DBCOLUMNDESC		*newCD = NULL, *oldCD	= NULL;
	DBORDINAL			newlen = 0, oldlen		= 0;
	DBID				*pColumnID				= NULL;
	DBCOLUMNDESC		*rgColumnDesc			= NULL;
	DBORDINAL			cColumnDesc				= 0;
	VARIANT				vSupportedTxnDDL;
	BOOL				fDDL_LOCK				= FALSE;

	TESTC_PROVIDER(VerifyInterface(m_pITableDefinition, IID_ITransactionLocal, 
			SESSION_INTERFACE, (IUnknown**)&pITransactionLocal));

	VariantInit(&vSupportedTxnDDL);
	TESTC_PROVIDER(GetProperty(DBPROP_SUPPORTEDTXNDDL, DBPROPSET_DATASOURCEINFO, 
			g_pIDBInitialize, &vSupportedTxnDDL));
	
	TESTC(VT_I4 == vSupportedTxnDDL.vt);
	// what values should we accept?
	TESTC_PROVIDER(DBPROPVAL_TC_NONE != vSupportedTxnDDL.lVal);

	DuplicateColumnDesc(m_rgColumnDesc, m_cColumnDesc, &rgColumnDesc);
	cColumnDesc = m_cColumnDesc;
	ReleaseAllColumnPropSets(rgColumnDesc, cColumnDesc);
	m_pTable->SetBuildColumnDesc(FALSE);
	m_pTable->SetColumnDesc(rgColumnDesc, cColumnDesc);
	
	// create a table and populate it
	TESTC_(m_hr = m_pTable->CreateTable(0, 0), S_OK);

	GetColumnDescOnTable(&m_pTable->GetTableID(), &oldCD, &oldlen);
	// start the transaction
	TESTC_(StartTransaction(pITransactionLocal), S_OK);

	// try to add a column to this maximum length name table
	if (rgColumnDesc[0].dbcid.uName.pwszName)
		PROVIDER_FREE(rgColumnDesc[0].dbcid.uName.pwszName);
	rgColumnDesc[0].dbcid.uName.pwszName = L"transacted_column";

	switch(vSupportedTxnDDL.lVal)
	{
		case DBPROPVAL_TC_DML:
			//check for XACT_E_XTIONEXISTS
			CHECK(m_hr = m_pITableDefinition->AddColumn(
				&m_pTable->GetTableID(), 
				&rgColumnDesc[0], 
				&pColumnID), XACT_E_XTIONEXISTS);
			break;

		case DBPROPVAL_TC_DDL_IGNORE:
			// the statement is not transacted
		case DBPROPVAL_TC_ALL:
		case DBPROPVAL_TC_DDL_COMMIT:
			CHECK(AddColumnAndCheck(&m_pTable->GetTableID(), 
				&rgColumnDesc[0], &pColumnID), S_OK);
			break;

		case DBPROPVAL_TC_DDL_LOCK:
			// error should be returned
			CHECK(m_pITableDefinition->AddColumn(
				&m_pTable->GetTableID(), 
				&rgColumnDesc[0], 
				&pColumnID), S_OK);
			break;
			
		default:
			TESTC(FALSE);
	}

	if (DBPROPVAL_TC_DDL_COMMIT != vSupportedTxnDDL.lVal)
	{
		// commit without retaining
		CHECK(m_hr = pITransactionLocal->Commit(FALSE, XACTTC_SYNC, 0), S_OK);
		//check the commit without retaining 
		CHECK(pITransactionLocal->Abort(NULL, FALSE, FALSE), FAILED(m_hr)? S_OK: XACT_E_NOTRANSACTION);
	}

	GetColumnDescOnTable(&m_pTable->GetTableID(), &newCD, &newlen);
	if (DBPROPVAL_TC_DML == vSupportedTxnDDL.lVal)
	{	// check column was not added
		COMPARE(AreColEqual(oldCD, oldlen, newCD, newlen), TRUE);
	}
	else
	{	// check column was added
		COMPARE(CheckColInfo(oldCD, oldlen, newCD, newlen, &rgColumnDesc[0]), TRUE);
	}
	ReleaseColumnDesc(newCD, newlen);

CLEANUP:
	if (rgColumnDesc)
		rgColumnDesc[0].dbcid.uName.pwszName = NULL;
	ReleaseColumnDesc(oldCD, oldlen);
	m_hr = m_pTable->DropTable();
	SAFE_RELEASE(pITransactionLocal);
	ReleaseDBID(pColumnID);
	TRETURN
}
// }}


// {{ TCW_VAR_PROTOTYPE(39)
//*-----------------------------------------------------------------------
// @mfunc Add a column for each provider type in an empty table => S_OK
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCAddColumn::Variation_39()
{ 
	TBEGIN
	DBORDINAL		i;
	WCHAR			*pwszName;
	DBID			*pColumnID		= NULL;
	DBCOLUMNDESC	*rgColumnDesc	= NULL;
	DBORDINAL		cColumnDesc		= 0;

	DuplicateColumnDesc(m_rgColumnDesc, m_cColumnDesc, &rgColumnDesc);
	cColumnDesc = m_cColumnDesc;
	ReleaseAllColumnPropSets(rgColumnDesc, cColumnDesc);
	m_pTable->SetBuildColumnDesc(FALSE);
	pwszName = rgColumnDesc[0].dbcid.uName.pwszName;
	m_pTable->SetColumnDesc(rgColumnDesc, 1);

	// for each type in DBCOLUMNDESC, add a column with maximum column size
	rgColumnDesc[0].dbcid.uName.pwszName = pwszName;
	for (i=0; i<cColumnDesc; i++)
	{
		// try to add a column from rgColumnDesc[i]
		odtLog <<	"column name:" << rgColumnDesc[i].dbcid.uName.pwszName << 
					" column type:" << rgColumnDesc[i].pwszTypeName << "\n";

		rgColumnDesc[0].dbcid.uName.pwszName = L"Initial_column";
		// create a table with a single column, equal to the first one in the row
		if (!CHECK(m_pTable->CreateTable(0, 0), S_OK))
			continue;

		rgColumnDesc[0].dbcid.uName.pwszName = pwszName;

		CHECK(AddColumnAndCheck(&m_pTable->GetTableID(), &rgColumnDesc[i], &pColumnID), S_OK);
		CHECK(m_pTable->DropTable(), S_OK);
		ReleaseDBID(pColumnID);
		pColumnID = NULL;
	}

	rgColumnDesc[0].dbcid.uName.pwszName = pwszName;
	m_pTable->SetNoOfColumnDesc(cColumnDesc);
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(40)
//*-----------------------------------------------------------------------
// @mfunc Add a column to a table created with a SQL command => S_OK
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCAddColumn::Variation_40()
{ 
	TBEGIN
	DBID				*pColumnID			= NULL;
	BOOL				fTableCreation;
	DBCOLUMNDESC		*rgColumnDesc		= NULL;
	DBORDINAL				cColumnDesc			= 0;
	IDBCreateCommand	*pIDBCreateCommand	= NULL;

	// check wheter the commands are supported
	TESTC_PROVIDER(VerifyInterface(m_pITableDefinition, IID_IDBCreateCommand,
		SESSION_INTERFACE, (IUnknown**)&pIDBCreateCommand));

	DuplicateColumnDesc(m_rgColumnDesc, m_cColumnDesc, &rgColumnDesc);
	cColumnDesc = m_cColumnDesc;
	ReleaseAllColumnPropSets(rgColumnDesc, cColumnDesc);
	m_pTable->SetBuildColumnDesc(FALSE);
	m_pTable->SetColumnDesc(rgColumnDesc, cColumnDesc-1);
	// set order for table creation
	fTableCreation = GetModInfo()->UseITableDefinition(FALSE);

	TESTC_(m_pTable->CreateTable(0, 0), S_OK);

	// try to add a column to this maximum length name table
	SAFE_FREE(rgColumnDesc[cColumnDesc-1].dbcid.uName.pwszName);
	rgColumnDesc[cColumnDesc-1].dbcid.uName.pwszName = wcsDuplicate(L"new_column");
	TESTC_(AddColumnAndCheck(&m_pTable->GetTableID(), &rgColumnDesc[cColumnDesc-1], &pColumnID), S_OK);

CLEANUP:
	m_pTable->DropTable();
	m_pTable->SetNoOfColumnDesc(cColumnDesc);
	GetModInfo()->UseITableDefinition(fTableCreation);
	ReleaseDBID(pColumnID);
	SAFE_RELEASE(pIDBCreateCommand);
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(41)
//*-----------------------------------------------------------------------
// @mfunc Drop all the column of a table (via SQL stmt) and then try to add a column => S_OK
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCAddColumn::Variation_41()
{ 
	TBEGIN
	DBID				*pColumnID = NULL;
	BOOL				fTableCreation;
	DB_LORDINAL			rgCol[1] = {1};
	DB_LORDINAL			*prgCol = rgCol;
	DBORDINAL			nCol = 1;
	DBCOLUMNDESC		*rgColumnDesc	= NULL;
	DBORDINAL			cColumnDesc		= 1;
	IDBCreateCommand	*pIDBCreateCommand	= NULL;

	// check whether commands are supported
	TESTC_PROVIDER(VerifyInterface(m_pITableDefinition, IID_IDBCreateCommand,
		SESSION_INTERFACE, (IUnknown**)&pIDBCreateCommand));

	DuplicateColumnDesc(m_rgColumnDesc, cColumnDesc, &rgColumnDesc);
	ReleaseAllColumnPropSets(rgColumnDesc, cColumnDesc);
	// create a table with a single column, using a SQL command
	fTableCreation = GetModInfo()->UseITableDefinition(FALSE);
	m_pTable->SetBuildColumnDesc(TRUE);

	TESTC_(m_pTable->CreateTable(0, 0), S_OK);

	// drop the only existing column from the table
	TESTC_PROVIDER(S_OK == m_pTable->ExecuteCommand(
						ALTER_TABLE_DROP_COLUMN,
						IID_NULL,
						NULL,						// the table name will be the implicit one
						NULL,						// don't return the command statement
						&nCol, 
						(DB_LORDINAL**)&prgCol,
						EXECUTE_IFNOERROR			// execute the command
						));

	// try to add a column to this table
	SAFE_FREE(rgColumnDesc[0].dbcid.uName.pwszName);
	rgColumnDesc[0].dbcid.uName.pwszName = wcsDuplicate(L"new_column");
	CHECK(AddColumnAndCheck(&m_pTable->GetTableID(), &rgColumnDesc[0], &pColumnID), S_OK);
	
	CHECK(m_pTable->DropTable(), S_OK);

CLEANUP:
	GetModInfo()->UseITableDefinition(fTableCreation);
	ReleaseColumnDesc(rgColumnDesc, cColumnDesc);
	ReleaseDBID(pColumnID);
	SAFE_RELEASE(pIDBCreateCommand);
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(42)
//*-----------------------------------------------------------------------
// @mfunc Non NULL pTypeInfo in DBCOLUMNDESC => DB_E_BADTYPE
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCAddColumn::Variation_42()
{ 
	TBEGIN
	DBID			*pColumnID		= NULL;
	DBCOLUMNDESC	*rgColumnDesc	= NULL;
	DBORDINAL		cColumnDesc		= 0;

	DuplicateColumnDesc(m_rgColumnDesc, m_cColumnDesc, &rgColumnDesc);
	cColumnDesc = m_cColumnDesc;
	ReleaseAllColumnPropSets(rgColumnDesc, cColumnDesc);
	m_pTable->SetBuildColumnDesc(FALSE);
	m_pTable->SetColumnDesc(rgColumnDesc, cColumnDesc-1);

	TESTC_(m_pTable->CreateTable(0, 0), S_OK);

	// try to add a column with a NULL value for name pointer
	rgColumnDesc[cColumnDesc-1].pTypeInfo = (ITypeInfo*)m_pITableDefinition;
	TESTC_(AddColumnAndCheck(&m_pTable->GetTableID(), &rgColumnDesc[cColumnDesc-1], 
		&pColumnID), DB_E_BADTYPE);			

CLEANUP:
	m_pTable->DropTable();
	rgColumnDesc[cColumnDesc-1].pTypeInfo = NULL;
	m_pTable->SetNoOfColumnDesc(cColumnDesc);
	ReleaseDBID(pColumnID);
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(43)
//*-----------------------------------------------------------------------
// @mfunc Missmatch between wType and pwszTypeName => DB_E_BADTYPE
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCAddColumn::Variation_43()
{ 
	TBEGIN
	DBORDINAL		i;
	DBID			*pColumnID		= NULL;
	DBCOLUMNDESC	*rgColumnDesc	= NULL;
	DBORDINAL		cColumnDesc		= 0;

	DuplicateColumnDesc(m_rgColumnDesc, m_cColumnDesc, &rgColumnDesc);
	cColumnDesc = m_cColumnDesc;
	ReleaseAllColumnPropSets(rgColumnDesc, cColumnDesc);
	m_pTable->SetBuildColumnDesc(FALSE);
	m_pTable->SetColumnDesc(rgColumnDesc, cColumnDesc-1);

	TESTC_(m_pTable->CreateTable(0, 0), S_OK);

	// try to add a column with a NULL value for name pointer
	for (i=0; i<cColumnDesc-1 && rgColumnDesc[i].wType == rgColumnDesc[cColumnDesc-1].wType; i++);
	TESTC_PROVIDER(i < cColumnDesc-2);

	if (rgColumnDesc[cColumnDesc-1].pwszTypeName)
		PROVIDER_FREE(rgColumnDesc[cColumnDesc-1].pwszTypeName);
	rgColumnDesc[cColumnDesc-1].pwszTypeName = wcsDuplicate(rgColumnDesc[i].pwszTypeName);
	
	TESTC_(AddColumnAndCheck(&m_pTable->GetTableID(), &rgColumnDesc[cColumnDesc-1], 
		&pColumnID), DB_E_BADTYPE);

CLEANUP:
	m_pTable->DropTable();
	m_pTable->SetNoOfColumnDesc(cColumnDesc);
	ReleaseDBID(pColumnID);
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(44)
//*-----------------------------------------------------------------------
// @mfunc Add a not nullable column and try to insert a null value for it
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCAddColumn::Variation_44()
{ 
	TBEGIN
	HRESULT			hr;
	DBID			*pColumnID = NULL;
	DBORDINAL		i;
	DBORDINAL		nCol[1];
	CCol			col;
	IRowsetChange	*pIRowsetChange = NULL;
	BOOL			fFound;
	DBCOLUMNDESC	*rgColumnDesc	= NULL;
	DBORDINAL		cColumnDesc		= 0;
	VARIANT			defval;

	DuplicateColumnDesc(m_rgColumnDesc, m_cColumnDesc, &rgColumnDesc);
	cColumnDesc = m_cColumnDesc;
	ReleaseAllColumnPropSets(rgColumnDesc, cColumnDesc);
	
	if (!SettableProperty(DBPROP_COL_NULLABLE, DBPROPSET_COLUMN) &&	2 > m_cColumnDesc)
	{
		TESTB = TEST_SKIPPED;
		goto CLEANUP1;
	}

	m_pTable->SetBuildColumnDesc(FALSE);

	// use all the types from the not nullable one (exclusive)
	m_pTable->SetColumnDesc(&rgColumnDesc[1], cColumnDesc-1);

	TESTC_(m_pTable->CreateTable(10, 0), S_OK);

	if (rgColumnDesc[0].dbcid.uName.pwszName)
		PROVIDER_FREE(rgColumnDesc[0].dbcid.uName.pwszName);
	rgColumnDesc[0].dbcid.uName.pwszName = L"NewColumn";
	SetProperty(&rgColumnDesc[0].rgPropertySets, &rgColumnDesc[0].cPropertySets, DBPROP_COL_NULLABLE, 
				VT_BOOL, (LPVOID)VARIANT_FALSE, DBPROPOPTIONS_REQUIRED, DB_NULLID, DBPROPSET_COLUMN);
	if (SettableProperty(DBPROP_COL_DEFAULT, DBPROPSET_COLUMN)) 
	{		
		VariantInit(&defval);
		GetDefaultValue(&rgColumnDesc[0], &defval);
		SetDefaultProperty(&rgColumnDesc[0].rgPropertySets, &rgColumnDesc[0].cPropertySets,
			&defval, DBPROPOPTIONS_OPTIONAL);	// might be not supported
		VariantClear(&defval);
	}

	TESTC_(AddColumnAndCheck(&m_pTable->GetTableID(), &rgColumnDesc[0], &pColumnID), S_OK);
	// must update info about table in m_pTable
	m_pTable->GetTableColumnInfo(&m_pTable->GetTableID());
	m_pTable->AddInfoFromColumnsSchemaRowset(m_pITableDefinition, 
		DBKIND_NAME != m_pTable->GetTableID().eKind? m_pTable->GetTableID().uName.pwszName: NULL);

	for (i=0, fFound=FALSE; !fFound && i<m_pTable->CountColumnsOnTable(); i++)
	{
		col = m_pTable->GetColInfoForUpdate(i+1);
		if (CompareDBID(rgColumnDesc[0].dbcid, *col.GetColID(), m_pIDBInitialize))
		{
			nCol[0]	= col.GetColNum();
			fFound	= TRUE;
		}
	}
	TESTC(fFound);
	TEST2C_(hr = m_pIOpenRowset->OpenRowset(NULL, &m_pTable->GetTableID(), NULL, 
		IID_IRowsetChange, 0, NULL, (IUnknown**)&pIRowsetChange), S_OK, E_NOINTERFACE);
	TESTC_PROVIDER(S_OK == hr);

	// try to insert a null value in a not null column
	hr = Insert(0, pIRowsetChange, NUMELEM(nCol), nCol);
	
	if (DB_E_NOTSUPPORTED != hr)
		CHECK(hr, DB_E_ERRORSOCCURRED);

CLEANUP:
	m_pTable->SetColumnDesc(NULL);
CLEANUP1:
	SAFE_RELEASE(pIRowsetChange);
	CHECK(m_pTable->DropTable(), S_OK);
	if (rgColumnDesc)
		rgColumnDesc[0].dbcid.uName.pwszName = NULL;
	ReleaseColumnDesc(rgColumnDesc, cColumnDesc);
	ReleaseDBID(pColumnID);
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(45)
//*-----------------------------------------------------------------------
// @mfunc Add a column on a view
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCAddColumn::Variation_45()
{ 
	TBEGIN
	DBID				TableID;
	DBID				*pColumnID = NULL;
	LPWSTR				pwszViewName = L"VirTab";
	DBCOLUMNDESC		*rgColumnDesc	= NULL;
	DBORDINAL			cColumnDesc		= 0;
	IDBCreateCommand	*pIDBCreateCommand	= NULL;

	// check whether commands are supported
	TESTC_PROVIDER(VerifyInterface(m_pITableDefinition, IID_IDBCreateCommand,
		SESSION_INTERFACE, (IUnknown**)&pIDBCreateCommand));

	DuplicateColumnDesc(m_rgColumnDesc, m_cColumnDesc, &rgColumnDesc);
	cColumnDesc = m_cColumnDesc;
	ReleaseAllColumnPropSets(rgColumnDesc, cColumnDesc);
	m_pTable->SetBuildColumnDesc(FALSE);
	m_pTable->SetColumnDesc(rgColumnDesc, cColumnDesc-1);

	TESTC_(m_pTable->CreateTable(10, 1), S_OK);

	m_pTable->SetViewName(pwszViewName);
	if ( !CHECK(m_pTable->ExecuteCommand(
						CREATE_VIEW,
						IID_NULL,
						pwszViewName,				// the table name will be the implicit one
						NULL,						// don't return the command statement
						0, 
						NULL,
						EXECUTE_IFNOERROR			// execute the command
						), S_OK) 
		)
	{
		odtLog << "\tA view on the table could not be created\n";
		goto CLEANUP;
	}

	// try to add a column to this maximum length name table
	PROVIDER_FREE(rgColumnDesc[cColumnDesc-1].dbcid.uName.pwszName);
	rgColumnDesc[cColumnDesc-1].dbcid.uName.pwszName = wcsDuplicate(L"new_column");
	// prepare the DBID to reflect the view
	TableID.eKind = DBKIND_NAME;
	TableID.uName.pwszName = pwszViewName;
	TEST3C_(AddColumnAndCheck(&TableID, &rgColumnDesc[cColumnDesc-1], &pColumnID), 
		E_FAIL, DB_E_NOTABLE, DB_SEC_E_PERMISSIONDENIED)

CLEANUP:
	SAFE_RELEASE(pIDBCreateCommand);
	ReleaseDBID(pColumnID);
	// drop the view!
	if (m_pTable->GetTableName())
		m_pTable->ExecuteCommand(
						DROP_VIEW,
						IID_NULL,
						pwszViewName,				// the table name will be the implicit one
						NULL,						// don't return the command statement
						0, 
						NULL,
						EXECUTE_IFNOERROR			// execute the command
						);
	CHECK(m_pTable->DropTable(), S_OK);
	m_pTable->SetNoOfColumnDesc(cColumnDesc);
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(46)
//*-----------------------------------------------------------------------
// @mfunc eKind != DBKIND_NAME for a column
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCAddColumn::Variation_46()
// try to use all the DBKIND values
{ 
	TBEGIN
	DBID			*pColumnID		= NULL;
	DBCOLUMNDESC	*rgColumnDesc	= NULL;
	DBORDINAL		cColumnDesc		= 0;

	DuplicateColumnDesc(m_rgColumnDesc, m_cColumnDesc, &rgColumnDesc);
	cColumnDesc = m_cColumnDesc;
	ReleaseAllColumnPropSets(rgColumnDesc, cColumnDesc);
	m_pTable->SetBuildColumnDesc(FALSE);
	m_pTable->SetColumnDesc(rgColumnDesc, cColumnDesc-1);

	TESTC_(m_hr = m_pTable->CreateTable(10, 0), S_OK);

	// try to add a column with different DBKIND values
	odtLog << "Add DBKIND_GUID_NAME column\n";
	if (rgColumnDesc[cColumnDesc-1].dbcid.uName.pwszName)
		PROVIDER_FREE(rgColumnDesc[cColumnDesc-1].dbcid.uName.pwszName);
	rgColumnDesc[cColumnDesc-1].dbcid.eKind				= DBKIND_GUID_NAME;
	rgColumnDesc[cColumnDesc-1].dbcid.uGuid.guid		= guidModule;
	rgColumnDesc[cColumnDesc-1].dbcid.uName.pwszName	= L"DBKIND_GUID_NAME";
	
	CHECK(AddColumnAndCheck(&m_pTable->GetTableID(), 
		&rgColumnDesc[cColumnDesc-1], &pColumnID), DB_E_BADCOLUMNID);

	ReleaseDBID(pColumnID);
	pColumnID = NULL;

	odtLog << "Add DBKIND_GUID_PROPID column\n";
	rgColumnDesc[cColumnDesc-1].dbcid.eKind				= DBKIND_GUID_PROPID;
	rgColumnDesc[cColumnDesc-1].dbcid.uName.ulPropid	= 0;
	
	CHECK(AddColumnAndCheck(&m_pTable->GetTableID(), 
		&rgColumnDesc[cColumnDesc-1], &pColumnID), DB_E_BADCOLUMNID);

	ReleaseDBID(pColumnID);
	pColumnID = NULL;
	
	odtLog << "Add DBKIND_NAME column\n";
	rgColumnDesc[cColumnDesc-1].dbcid.eKind				= DBKIND_NAME;
	rgColumnDesc[cColumnDesc-1].dbcid.uName.pwszName	= L"DBKIND_NAME";
	
	CHECK(AddColumnAndCheck(&m_pTable->GetTableID(), 
		&rgColumnDesc[cColumnDesc-1], &pColumnID), S_OK);

	ReleaseDBID(pColumnID);
	pColumnID = NULL;

	odtLog << "Add DBKIND_PGUID_NAME column\n";
	rgColumnDesc[cColumnDesc-1].dbcid.eKind				= DBKIND_PGUID_NAME;
	rgColumnDesc[cColumnDesc-1].dbcid.uName.pwszName	= L"DBKIND_PGUID_NAME";
	rgColumnDesc[cColumnDesc-1].dbcid.uGuid.pguid		= &guidModule;
	
	CHECK(AddColumnAndCheck(&m_pTable->GetTableID(), 
		&rgColumnDesc[cColumnDesc-1], &pColumnID), DB_E_BADCOLUMNID);

	ReleaseDBID(pColumnID);
	pColumnID = NULL;

	odtLog << "Add DBKIND_PGUID_PROPID column\n";
	rgColumnDesc[cColumnDesc-1].dbcid.eKind				= DBKIND_PGUID_PROPID;
	rgColumnDesc[cColumnDesc-1].dbcid.uName.ulPropid	= 0;
	rgColumnDesc[cColumnDesc-1].dbcid.uGuid.pguid		= &guidModule;
	
	CHECK(AddColumnAndCheck(&m_pTable->GetTableID(), 
		&rgColumnDesc[cColumnDesc-1], &pColumnID), DB_E_BADCOLUMNID);

	ReleaseDBID(pColumnID);
	pColumnID = NULL;

	odtLog << "Add DBKIND_PROPID column\n";
	rgColumnDesc[cColumnDesc-1].dbcid.eKind				= DBKIND_PROPID;
	rgColumnDesc[cColumnDesc-1].dbcid.uName.ulPropid	= 0;
	
	CHECK(AddColumnAndCheck(&m_pTable->GetTableID(), 
		&rgColumnDesc[cColumnDesc-1], &pColumnID), DB_E_BADCOLUMNID);

	ReleaseDBID(pColumnID);
	pColumnID = NULL;

	odtLog << "Add DBKIND_GUID column\n";
	rgColumnDesc[cColumnDesc-1].dbcid.eKind				= DBKIND_GUID;
	rgColumnDesc[cColumnDesc-1].dbcid.uName.ulPropid	= 0;

	CHECK(AddColumnAndCheck(&m_pTable->GetTableID(), 
		&rgColumnDesc[cColumnDesc-1], &pColumnID), DB_E_BADCOLUMNID);

	ReleaseDBID(pColumnID);
	pColumnID = NULL;

CLEANUP:
	CHECK(m_pTable->DropTable(), S_OK);
	rgColumnDesc[cColumnDesc-1].dbcid.uName.pwszName = NULL;
	m_pTable->SetNoOfColumnDesc(cColumnDesc);
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




//---------------------------------------------------------------------
//
// @cmember Thread funtion for TCAddColumn
//---------------------------------------------------------------------
unsigned TCAddColumn::MyThreadProc(ULONG i)
{
	DBCOLUMNDESC	*pColumnDesc = NULL;
	HRESULT			hr;

	if (i>= nThreads)
		return 0;
	DuplicateColumnDesc(m_rgColumnDesc, 1, &pColumnDesc);
	ReleaseDBID(&pColumnDesc->dbcid, FALSE);
	pColumnDesc->dbcid.eKind			= DBKIND_NAME;
	pColumnDesc->dbcid.uName.pwszName	= m_rgName[i];
	Sleep(0); // switch the context

	
  	hr = m_pITableDefinition->AddColumn(&m_pTable->GetTableID(), pColumnDesc, NULL);
	Sleep(0); // switch the context

	pColumnDesc->dbcid.uName.pwszName = NULL;
	ReleaseColumnDesc(pColumnDesc, 1);
	m_rgResult[i] = hr;
	return 1;
} //TCAddColumn::MyThreadProc




// {{ TCW_VAR_PROTOTYPE(47)
//*-----------------------------------------------------------------------
// @mfunc threads with different column
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCAddColumn::Variation_47()
{ 
	unsigned		rgIDThread[nThreads];
	HANDLE			hrgThread[nThreads];
	CInParam		rgThreadParam[nThreads];
	BOOL			fTestResult = TEST_FAIL;
	ULONG			i;
	LPWSTR			pwszBaseName = NULL;
	WCHAR			number[3];
	DBCOLUMNDESC	*rgColumnDesc	= NULL;
	ULONG			cColumnDesc		= 1;

	DuplicateColumnDesc(m_rgColumnDesc, cColumnDesc, &rgColumnDesc);
	ReleaseAllColumnPropSets(rgColumnDesc, cColumnDesc);
	m_pTable->SetBuildColumnDesc(FALSE);
	m_pTable->SetColumnDesc(rgColumnDesc, cColumnDesc);

	// create n names and init the results
	for (i=0; i<nThreads; i++)
		m_rgName[i] = NULL;

	TESTC_(m_hr = m_pTable->CreateTable(0, 0), S_OK);

	pwszBaseName = m_pTable->GetTableName();
	for (i=0; i< nThreads; i++)
	{
		m_rgResult[i] = -1;
		m_rgName[i] = (WCHAR*)PROVIDER_ALLOC((3+wcslen(pwszBaseName))*sizeof(WCHAR));		
		ASSERT(m_rgName[i]);
		wcscpy(m_rgName[i], pwszBaseName);
		swprintf(number, L"%02d", i);
		wcscat(m_rgName[i], number);
		rgThreadParam[i].pObject	= this;
		rgThreadParam[i].i			= i;
	}
	
	// creates a table, build rgColumnDesc by it
	for (i=0; i<nThreads; i++)
	{
		hrgThread[i] = (HANDLE)_beginthreadex(NULL, 0, ThreadProc,
							(void*)&rgThreadParam[i],
							0, 
							&rgIDThread[i]);		// input param
		TESTC(0 != hrgThread[i]);
	}

	WaitForMultipleObjects(nThreads, (CONST HANDLE*)hrgThread, TRUE, 1000);
	Sleep(1000);
	for (i=0; i< nThreads; i++)
		CloseHandle(hrgThread[i]);

	for (i=0; i<nThreads; i++)
		TESTC_(m_rgResult[i], S_OK);
	fTestResult = TEST_PASS;

CLEANUP:
	DropTableAndCheck(&m_pTable->GetTableID());
	for (i=0; i<nThreads; i++)
		PROVIDER_FREE(m_rgName[i]);
	return fTestResult;
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(48)
//*-----------------------------------------------------------------------
// @mfunc threads on the same column
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCAddColumn::Variation_48()
{ 
	unsigned		rgIDThread[nThreads];
	HANDLE			hrgThread[nThreads];
	CInParam		rgThreadParam[nThreads];
	BOOL			fTestResult = TEST_FAIL;
	ULONG			i, nS_OK, nDB_E_DUPLICATECOLUMNID;
	DBCOLUMNDESC	*rgColumnDesc	= NULL;
	ULONG			cColumnDesc		= 1;

	DuplicateColumnDesc(m_rgColumnDesc, cColumnDesc, &rgColumnDesc);
	ReleaseAllColumnPropSets(rgColumnDesc, cColumnDesc);
	m_pTable->SetBuildColumnDesc(FALSE);
	m_pTable->SetColumnDesc(rgColumnDesc, cColumnDesc);
	TESTC_(m_hr = m_pTable->CreateTable(0, 0), S_OK);

	for (i=0; i< nThreads; i++)
	{
		m_rgResult[i] = -1;
		m_rgName[i] = L"someOtherColumn";		
		rgThreadParam[i].pObject	= this;
		rgThreadParam[i].i			= i;
	}
	
	// creates a table, build rgColumnDesc by it
	for (i=0; i<nThreads; i++)
	{
		hrgThread[i] = (HANDLE)_beginthreadex(NULL, 0, ThreadProc,
							(void*)&rgThreadParam[i],
							0, 
							&rgIDThread[i]);		// input param
		TESTC(0 != hrgThread[i]);
	}

	WaitForMultipleObjects(nThreads, (CONST HANDLE*)hrgThread, TRUE, 1000);
	Sleep(1000);
	for (i=0; i< nThreads; i++)
		CloseHandle(hrgThread[i]);

	for (i=nS_OK=nDB_E_DUPLICATECOLUMNID=0; i<nThreads; i++)
	{
		if (m_rgResult[i] == S_OK)
			nS_OK++;
		else if (CHECK(m_rgResult[i], DB_E_DUPLICATECOLUMNID))
			nDB_E_DUPLICATECOLUMNID++;
		else
			goto CLEANUP;
	}
	TESTC(nS_OK== 1 && nDB_E_DUPLICATECOLUMNID == nThreads-1);
	fTestResult = TEST_PASS;

CLEANUP:
	DropTableAndCheck(&m_pTable->GetTableID());
	return fTestResult;
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(49)
//*-----------------------------------------------------------------------
// @mfunc add columns of alll known wType => S_OK
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCAddColumn::Variation_49()
{ 
	TBEGIN
	DBORDINAL		i;
	DBID			*pColumnID		= NULL;
	DBCOLUMNDESC	*pColumnDesc	= NULL;
	DBCOLUMNDESC	*rgColumnDesc	= NULL;
	DBORDINAL		cColumnDesc		= 0;

	DuplicateColumnDesc(m_rgColumnDesc, m_cColumnDesc, &rgColumnDesc);
	cColumnDesc = m_cColumnDesc;
	ReleaseAllColumnPropSets(rgColumnDesc, cColumnDesc);
	m_pTable->SetBuildColumnDesc(FALSE);

	DuplicateColumnDesc(&rgColumnDesc[0], 1, &pColumnDesc);
	PROVIDER_FREE(pColumnDesc[0].dbcid.uName.pwszName);
	pColumnDesc[0].dbcid.uName.pwszName = wcsDuplicate(L"ColoanaInitiala");
	m_pTable->SetColumnDesc(pColumnDesc, 1);

	for (i=0; i<cColumnDesc; i++)
	{
		// create a table with a single column, equal to the first one in the row
		if (!CHECK(m_hr = m_pTable->CreateTable(0, 0), S_OK)) 
			continue;

		// try to add a column from rgColumnDesc[i] with a NULL name and a valid wType
		PROVIDER_FREE(rgColumnDesc[i].pwszTypeName);
		odtLog <<	"column name: " << rgColumnDesc[i].dbcid.uName.pwszName << "\n";
		
		CHECK(AddColumnAndCheck(&m_pTable->GetTableID(), &rgColumnDesc[i], &pColumnID), S_OK);

		CHECK(m_pTable->DropTable(), S_OK);
		ReleaseDBID(pColumnID);
		pColumnID = NULL;
	}

	ReleaseColumnDesc(rgColumnDesc, cColumnDesc);
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(50)
//*-----------------------------------------------------------------------
// @mfunc Fully Qualified table name
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCAddColumn::Variation_50()
{ 
	TBEGIN
	DBID			TableID;
	DBID			BaseTableID;
	WCHAR			*pwszQualTableName	= NULL;
	WCHAR			*pwszCatalogName	= NULL;
	WCHAR			*pwszSchemaName		= NULL;
	WCHAR			*pwszTableName		= NULL;
	DBCOLUMNDESC	*rgColumnDesc		= NULL;
	DBORDINAL		cColumnDesc			= 0;

	// create a regular table
	TESTC(NULL != m_pTable);
	m_pTable->SetBuildColumnDesc(TRUE);
	TESTC_(m_pTable->CreateTable(0, 0), S_OK);
	pwszTableName = m_pTable->GetTableName();
	TableID.eKind = DBKIND_NAME;
	
	BaseTableID.eKind = DBKIND_NAME;
	BaseTableID.uName.pwszName = pwszTableName; 

	TESTC(GetCatalogSchemaNames(pwszTableName, &pwszCatalogName, &pwszSchemaName));

	//Construct a fully Qualified TableName...
	TESTC_(m_pTable->GetQualifiedName(pwszCatalogName, pwszSchemaName, pwszTableName, &pwszQualTableName),S_OK);
	TableID.uName.pwszName = pwszQualTableName;

	m_pTable->BuildColumnDescs(&rgColumnDesc);
	m_pTable->SetColumnDesc(rgColumnDesc, cColumnDesc=m_pTable->CountColumnsOnTable());
	ReleaseAllColumnPropSets(rgColumnDesc, cColumnDesc);
	ReleaseDBID(&rgColumnDesc[0].dbcid, FALSE);
	rgColumnDesc[0].dbcid.eKind = DBKIND_NAME;
	rgColumnDesc[0].dbcid.uName.pwszName = wcsDuplicate(L"AltaColoana");

	TESTC_(AddColumnAndCheck(&TableID, &rgColumnDesc[0], NULL, NULL, &BaseTableID), S_OK);
    
CLEANUP:
	SAFE_FREE(pwszCatalogName);
	SAFE_FREE(pwszSchemaName);
	SAFE_FREE(pwszQualTableName);
	m_pTable->DropTable();
    TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(51)
//*-----------------------------------------------------------------------
// @mfunc Quoted Table Name
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCAddColumn::Variation_51()
{ 
	TBEGIN
	DBID			TableID;
	DBCOLUMNDESC	*rgColumnDesc	= NULL;
	DBORDINAL		cColumnDesc		= 0;
	
	TableID.eKind = DBKIND_NAME;
	TableID.uName.pwszName = NULL;
	TESTC(NULL != m_pTable);
	m_pTable->SetBuildColumnDesc(TRUE);
	TESTC_(m_pTable->CreateTable(0, 0), S_OK);

	m_pTable->GetQuotedName(m_pTable->GetTableName(), &TableID.uName.pwszName);

	m_pTable->BuildColumnDescs(&rgColumnDesc);
	m_pTable->SetColumnDesc(rgColumnDesc, cColumnDesc=m_pTable->CountColumnsOnTable());
	ReleaseAllColumnPropSets(rgColumnDesc, cColumnDesc);
	ReleaseDBID(&rgColumnDesc[0].dbcid, FALSE);
	rgColumnDesc[0].dbcid.eKind = DBKIND_NAME;
	rgColumnDesc[0].dbcid.uName.pwszName = wcsDuplicate(L"AltaColoana");

	TESTC_(AddColumnAndCheck(&TableID, &rgColumnDesc[0], NULL), S_OK);

CLEANUP:
	ReleaseDBID(&TableID, FALSE);
	m_pTable->DropTable();
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(52)
//*-----------------------------------------------------------------------
// @mfunc pColumnDesc == NULL => E_INVALIDARG
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCAddColumn::Variation_52()
{ 
	TBEGIN
	DBID			*pColumnID		= NULL;
	DBCOLUMNDESC	*rgColumnDesc	= NULL;
	DBORDINAL		cColumnDesc		= 0;

	DuplicateColumnDesc(m_rgColumnDesc, m_cColumnDesc, &rgColumnDesc);
	cColumnDesc = m_cColumnDesc;
	ReleaseAllColumnPropSets(rgColumnDesc, cColumnDesc);
	m_pTable->SetColumnDesc(rgColumnDesc, cColumnDesc-1);
	m_pTable->SetBuildColumnDesc(FALSE);

	TESTC_(m_hr = m_pTable->CreateTable(0, 0), S_OK);

	TESTC_(AddColumnAndCheck(&m_pTable->GetTableID(), NULL, &pColumnID), E_INVALIDARG);

CLEANUP:
	CHECK(m_pTable->DropTable(), S_OK);
	m_pTable->SetNoOfColumnDesc(cColumnDesc);
	ReleaseDBID(pColumnID);
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(53)
//*-----------------------------------------------------------------------
// @mfunc cPropertySets != 0 and rgPropertySets == NULL in pColumnDesc => E_INVALIDARG
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCAddColumn::Variation_53()
{ 
	TBEGIN
	DBID			*pColumnID		= NULL;
	DBCOLUMNDESC	*rgColumnDesc	= NULL;
	DBORDINAL		cColumnDesc		= 0;

	DuplicateColumnDesc(m_rgColumnDesc, m_cColumnDesc, &rgColumnDesc);
	cColumnDesc = m_cColumnDesc;
	ReleaseAllColumnPropSets(rgColumnDesc, cColumnDesc);
	m_pTable->SetBuildColumnDesc(FALSE);
	m_pTable->SetColumnDesc(rgColumnDesc, cColumnDesc-1);

	TESTC_(m_hr = m_pTable->CreateTable(10, 0), S_OK);
	// try to add a column with a bad wType
	rgColumnDesc[cColumnDesc-1].cPropertySets	= (BYTE)(rand()%255+1);
	rgColumnDesc[cColumnDesc-1].rgPropertySets	= NULL;
	
	TESTC_(AddColumnAndCheck(&m_pTable->GetTableID(), &rgColumnDesc[cColumnDesc-1], 
		&pColumnID), E_INVALIDARG);

CLEANUP:
	ReleaseDBID(pColumnID);
	CHECK(m_pTable->DropTable(), S_OK);
	// restore the proper number of properties for the column
	rgColumnDesc[cColumnDesc-1].cPropertySets = 0;
	m_pTable->SetNoOfColumnDesc(cColumnDesc);
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(54)
//*-----------------------------------------------------------------------
// @mfunc cPropertySets == 0 and rgPropertySets != NULL in pColumnDesc => S_OK
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCAddColumn::Variation_54()
{ 
	TBEGIN
	DBID			*pColumnID		= NULL;
	DBCOLUMNDESC	*rgColumnDesc	= NULL;
	DBORDINAL		cColumnDesc		= 0;
	DBPROPSET		rgPropertySets[1];

	DuplicateColumnDesc(m_rgColumnDesc, m_cColumnDesc, &rgColumnDesc);
	cColumnDesc = m_cColumnDesc;
	ReleaseAllColumnPropSets(rgColumnDesc, cColumnDesc);
	m_pTable->SetBuildColumnDesc(FALSE);
	m_pTable->SetColumnDesc(rgColumnDesc, cColumnDesc-1);

	TESTC_(m_hr = m_pTable->CreateTable(10, 0), S_OK);
	// try to add a column with a bad wType
	rgColumnDesc[cColumnDesc-1].cPropertySets	= 0;
	rgColumnDesc[cColumnDesc-1].rgPropertySets	= rgPropertySets;
	memset(rgPropertySets, 0, sizeof(DBPROPSET));

	TESTC_(AddColumnAndCheck(&m_pTable->GetTableID(), &rgColumnDesc[cColumnDesc-1], 
		&pColumnID), S_OK);

CLEANUP:
	rgColumnDesc[cColumnDesc-1].rgPropertySets	= NULL;
	ReleaseDBID(pColumnID);
	CHECK(m_pTable->DropTable(), S_OK);
	// restore the property set array
	rgColumnDesc[cColumnDesc-1].rgPropertySets = NULL;
	m_pTable->SetNoOfColumnDesc(cColumnDesc);
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(55)
//*-----------------------------------------------------------------------
// @mfunc cProperties == 0 and rgProperties != NULL in pColumnDesc's propset => S_OK
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCAddColumn::Variation_55()
{ 
	TBEGIN
	DBID			*pColumnID		= NULL;
	DBCOLUMNDESC	*rgColumnDesc	= NULL;
	DBORDINAL		cColumnDesc		= 0;
	DBPROPSET		rgPropertySets[1];
	DBPROP			rgProperties[1];

	DuplicateColumnDesc(m_rgColumnDesc, m_cColumnDesc, &rgColumnDesc);
	cColumnDesc = m_cColumnDesc;
	ReleaseAllColumnPropSets(rgColumnDesc, cColumnDesc);
	m_pTable->SetBuildColumnDesc(FALSE);
	m_pTable->SetColumnDesc(rgColumnDesc, cColumnDesc-1);

	TESTC_(m_hr = m_pTable->CreateTable(10, 0), S_OK);
	// try to add a column with a bad wType
	rgColumnDesc[cColumnDesc-1].cPropertySets	= NUMELEM(rgPropertySets);
	rgColumnDesc[cColumnDesc-1].rgPropertySets	= rgPropertySets;
	memset(rgPropertySets, 0, sizeof(DBPROPSET));
	rgPropertySets[0].guidPropertySet	= DBPROPSET_COLUMN;
	rgPropertySets[0].cProperties		= 0;
	rgPropertySets[0].rgProperties		= rgProperties;

	TESTC_(AddColumnAndCheck(&m_pTable->GetTableID(), 
				&rgColumnDesc[cColumnDesc-1], &pColumnID), S_OK);

CLEANUP:
	rgColumnDesc[cColumnDesc-1].rgPropertySets	= NULL;
	ReleaseDBID(pColumnID);
	CHECK(m_pTable->DropTable(), S_OK);
	// restore the prop array
	rgPropertySets[0].rgProperties = NULL;
	m_pTable->SetNoOfColumnDesc(cColumnDesc);
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(56)
//*-----------------------------------------------------------------------
// @mfunc cProperties != 0 and rgProperties == NULL in pColumnDesc's propset => E_INVALIDARG
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCAddColumn::Variation_56()
{ 
	TBEGIN
	DBID			*pColumnID		= NULL;
	DBCOLUMNDESC	*rgColumnDesc	= NULL;
	DBORDINAL		cColumnDesc		= 0;
	DBPROPSET		rgPropertySets[1];

	DuplicateColumnDesc(m_rgColumnDesc, m_cColumnDesc, &rgColumnDesc);
	cColumnDesc = m_cColumnDesc;
	ReleaseAllColumnPropSets(rgColumnDesc, cColumnDesc);
	m_pTable->SetBuildColumnDesc(FALSE);
	m_pTable->SetColumnDesc(rgColumnDesc, cColumnDesc-1);

	TESTC_(m_pTable->CreateTable(10, 0), S_OK);

	// built the property set array
	rgColumnDesc[cColumnDesc-1].cPropertySets	= NUMELEM(rgPropertySets);
	rgColumnDesc[cColumnDesc-1].rgPropertySets	= rgPropertySets;
	memset(rgPropertySets, 0, sizeof(DBPROPSET));
	rgPropertySets[0].guidPropertySet	= DBPROPSET_COLUMN;
	rgPropertySets[0].cProperties		= (BYTE)(rand()%255+1);
	rgPropertySets[0].rgProperties		= NULL;

	TESTC_(AddColumnAndCheck(&m_pTable->GetTableID(), 
				&rgColumnDesc[cColumnDesc-1], &pColumnID), E_INVALIDARG);

CLEANUP:
	rgColumnDesc[cColumnDesc-1].rgPropertySets	= NULL;
	ReleaseDBID(pColumnID);
	CHECK(m_pTable->DropTable(), S_OK);
	// restore the prop counter
	rgPropertySets[0].cProperties = 0;
	m_pTable->SetNoOfColumnDesc(cColumnDesc);
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(57)
//*-----------------------------------------------------------------------
// @mfunc pclsid not null
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCAddColumn::Variation_57()
{ 
	TBEGIN
	DBID			*pColumnID		= NULL;
	DBCOLUMNDESC	*rgColumnDesc	= NULL;
	DBORDINAL		cColumnDesc		= 0;
	HRESULT			hr;
	POSITION		pos;
	CCol			col;
	BOOL			fOleSupported	= FALSE;

	DuplicateColumnDesc(m_rgColumnDesc, m_cColumnDesc, &rgColumnDesc);
	cColumnDesc = m_cColumnDesc;
	ReleaseAllColumnPropSets(rgColumnDesc, cColumnDesc);
	m_pTable->SetBuildColumnDesc(FALSE);
	m_pTable->SetColumnDesc(rgColumnDesc, cColumnDesc-1);

	TESTC_(m_pTable->CreateTable(10, 0), S_OK);

	// set pclsid to IID_NULL
	rgColumnDesc[cColumnDesc-1].pclsid = (GUID*)&IID_NULL;

	// check that pclsid is ignored
	TESTC_(AddColumnAndCheck(&m_pTable->GetTableID(), 
				&rgColumnDesc[cColumnDesc-1], &pColumnID),S_OK);

	TESTC_(m_pTable->DropTable(), S_OK);
	TESTC_(m_pTable->CreateTable(10, 0), S_OK);

	// check DBTYPE_IUNKNOWN is supported
	for (pos = m_ColList.GetHeadPosition(); pos; )
	{
		col = m_ColList.GetNext(pos);
		if (DBTYPE_IUNKNOWN == col.GetProviderType())
		{
			fOleSupported = TRUE;
			break;
		}
	}

	// check whether a DBTYPE_IUNKNOWN column can be created in the table
	rgColumnDesc[cColumnDesc-1].wType	= DBTYPE_IUNKNOWN;
	PROVIDER_FREE(rgColumnDesc[cColumnDesc-1].pwszTypeName);
	if (fOleSupported)
		rgColumnDesc[cColumnDesc-1].pwszTypeName = wcsDuplicate(col.GetProviderTypeName());
	hr = fOleSupported ? S_OK : DB_E_BADTYPE;
	
	TESTC_(AddColumnAndCheck(&m_pTable->GetTableID(), &rgColumnDesc[cColumnDesc-1], 
		&pColumnID), hr);
	

CLEANUP:
	ReleaseDBID(pColumnID);
	CHECK(m_pTable->DropTable(), S_OK);
	m_pTable->SetNoOfColumnDesc(cColumnDesc);
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(58)
//*-----------------------------------------------------------------------
// @mfunc NULL pwszTypeName => S_OK
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCAddColumn::Variation_58()
{ 
	TBEGIN
	DBID			*pColumnID		= NULL;
	DBCOLUMNDESC	*rgColumnDesc	= NULL;
	DBORDINAL		cColumnDesc		= 0;

	DuplicateColumnDesc(m_rgColumnDesc, m_cColumnDesc, &rgColumnDesc);
	cColumnDesc = m_cColumnDesc;
	ReleaseAllColumnPropSets(rgColumnDesc, cColumnDesc);
	m_pTable->SetBuildColumnDesc(FALSE);
	m_pTable->SetColumnDesc(rgColumnDesc, cColumnDesc-1);

	TESTC_(m_hr = m_pTable->CreateTable(10, 0), S_OK);
	// try to add a column with a bad wType
	PROVIDER_FREE(rgColumnDesc[cColumnDesc-1].pwszTypeName);
	rgColumnDesc[cColumnDesc-1].pwszTypeName = NULL;
	
	TESTC_(AddColumnAndCheck(&m_pTable->GetTableID(), &rgColumnDesc[cColumnDesc-1], 
		&pColumnID), S_OK);

CLEANUP:
	CHECK(m_pTable->DropTable(), S_OK);
	m_pTable->SetNoOfColumnDesc(cColumnDesc);
	ReleaseDBID(pColumnID);
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END


// {{ TCW_TERMINATE_METHOD
//--------------------------------------------------------------------
// @mfunc TestCase Termination Routine
//
// @rdesc TRUE or FALSE
//
BOOL TCAddColumn::Terminate()
{
	// {{ TCW_TERM_BASECLASS_CHECK2
	return(TCITableDefinition::Terminate());
}	// }}
// }}
// }}




// {{ TCW_TC_PROTOTYPE(TCDropColumn)
//*-----------------------------------------------------------------------
//| Test Case:		TCDropColumn - Test case for dropping columns
//|	Created:			09/11/97
//*-----------------------------------------------------------------------

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




/*
//----------------------------------------------------------------------
//
// @cmember Check whether the 2 list of columns are identical, 
// excepting column n
//----------------------------------------------------------------------
BOOL TCDropColumn::IsColumnDifferention(
	DBCOLUMNDESC	*newlist, 
	ULONG			newlen, 
	DBCOLUMNDESC	*oldlist, 
	ULONG			oldlen, 
	ULONG			n
)
{
	ULONG	nNewCol;
	ULONG	nOldCol;

	if (!newlist || !oldlist)
		return oldlist == newlist;
	if (newlen != oldlen - 1)
		return FALSE;
	
	// it is assumed that the columns should be identical up to column n
	// the new column n will be the oldcolumn n+1, the new column n+1		
	// should be identical to the old column n+2, etc
	for (nNewCol = nOldCol = 0; nNewCol < newlen; nNewCol++)
	{
		if (nNewCol == n)
			nOldCol++;
		if (!CompareDBID(newlist[nNewCol].dbcid, oldlist[nOldCol++].dbcid, m_pIDBInitialize))
			return FALSE;
	}
	return TRUE;
} //TCDropColumn::IsColumnDifferention
//----------------------------------------------------------------------
//
// @cmember Check whether the 2 list of columns are identical
//----------------------------------------------------------------------
BOOL TCDropColumn::ListEqual(DBCOLUMNDESC *newlist, ULONG newlen, DBCOLUMNDESC *oldlist, ULONG oldlen)
{
	ULONG	i;

	if (!newlist || !oldlist)
		return newlist == oldlist;
	if (newlen != oldlen)
		return FALSE;
	for (i=0; i<newlen; i++)
		if (!CompareDBID(newlist[i].dbcid, oldlist[i].dbcid, m_pIDBInitialize))
			return FALSE;
	return TRUE;
} //TCDropColumn::ListEqual
*/




// {{ TCW_VAR_PROTOTYPE(1)
//*-----------------------------------------------------------------------
// @mfunc pTableID is NULL => E_INVALIDARG
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCDropColumn::Variation_1()
{
	TBEGIN
	DBID	ColumnID;

	ColumnID.eKind		= DBKIND_NAME;
	ColumnID.uName.pwszName	= L"Gateway2001";

	TESTC_(DropColumnAndCheck(NULL, &ColumnID), E_INVALIDARG);
CLEANUP:
	TRETURN
}
// }}


// {{ TCW_VAR_PROTOTYPE(2)
//*-----------------------------------------------------------------------
// @mfunc pColumnID in NULL => E_INVALIDARG
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCDropColumn::Variation_2()
{
	TBEGIN

	TESTC_(m_hr = m_pTable->CreateTable(0, 0), S_OK);

	TESTC_(DropColumnAndCheck(&m_pTable->GetTableID(), NULL), E_INVALIDARG);

CLEANUP:
	CHECK(m_pTable->DropTable(), S_OK);
	TRETURN
}
// }}


// {{ TCW_VAR_PROTOTYPE(3)
//*-----------------------------------------------------------------------
// @mfunc *pTableID is DB_NULLID => DB_E_NOTABLE
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCDropColumn::Variation_3()
{
	TBEGIN
	DBID	ColumnID;
	DBID	TableID			= DB_NULLID;

	ColumnID.eKind			= DBKIND_NAME;
	ColumnID.uName.pwszName	= L"Gateway2001";
	
	TESTC_(DropColumnAndCheck(&TableID, &ColumnID), DB_E_NOTABLE);

CLEANUP:
	TRETURN
}
// }}


// {{ TCW_VAR_PROTOTYPE(4)
//*-----------------------------------------------------------------------
// @mfunc *pColumnID is DB_NULLID => DB_E_NOCOLUMN
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCDropColumn::Variation_4()
{
	TBEGIN
	DBID	ColumnID;

	memset(&ColumnID, 0, sizeof(DBID));
	TESTC_(m_pTable->CreateTable(0, 0), S_OK);

	//NOTE: spec was changed in MDAC 2.6 to replace DB_E_BADCOLUMNID with DB_E_NOCOLUMN 
	//		for ITableDefinition::DropColumn. So when runnning against MDAC 2.5 expect DB_E_BADCOLUMNID
	//      This is for SQL-specific provider. For other providers, you should modify this to test against your target spec
	TESTC_(DropColumnAndCheck(&m_pTable->GetTableID(), &ColumnID), g_fSQLOLEDB25 ? DB_E_BADCOLUMNID : DB_E_NOCOLUMN);

CLEANUP:
	CHECK(m_pTable->DropTable(), S_OK);
	TRETURN
}
// }}


// {{ TCW_VAR_PROTOTYPE(5)
//*-----------------------------------------------------------------------
// @mfunc Maximum length table name => S_OK
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCDropColumn::Variation_5()
{
	TBEGIN
	DBID			ColumnID;
	DBID			TableID;
	DBORDINAL		n, cColumns;
	DBCOLUMNINFO	*rgColInfo = NULL;
	LPWSTR			pwszTableName;
	OLECHAR			*pStringBuffer = NULL;
	DBORDINAL		ulOrdinal = 0;

	m_pTable->MakeTableName(NULL);
	TableID.eKind			= DBKIND_NAME;
	TableID.uName.pwszName	= pwszTableName = BuildValidName(m_cMaxTableName, m_pTable->GetTableName());
	PRVTRACE(L"** TCDropColumn::Variation_5(): create a table with max table name: %s, %d\n", 
			pwszTableName, n=wcslen(pwszTableName));

	TESTC_(m_hr = m_pTable->CreateTable(0, 0, pwszTableName), S_OK);

	GetColumnInfo(&TableID, &cColumns, &rgColInfo, &pStringBuffer);
	TESTC(0 < cColumns);
	// check if the first column is bookmark or not
	if (0 == rgColInfo[0].iOrdinal)
		ulOrdinal = 1;

	TESTC(ulOrdinal < cColumns);
	ColumnID.eKind			= DBKIND_NAME;
	ColumnID.uName.pwszName	= rgColInfo[ulOrdinal].pwszName;

	TESTC_(DropColumnAndCheck(&m_pTable->GetTableID(), &ColumnID), S_OK);

CLEANUP:
	CHECK(m_hr = m_pTable->DropTable(), S_OK);
	PROVIDER_FREE(pStringBuffer);
	PROVIDER_FREE(rgColInfo);
	PROVIDER_FREE(pwszTableName);
	TRETURN
}
// }}


// {{ TCW_VAR_PROTOTYPE(6)
//*-----------------------------------------------------------------------
// @mfunc 1-char-too long table name => DB_E_NOTABLE
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCDropColumn::Variation_6()
{
	BOOL			fTestRes = TEST_FAIL; 
	DBID			ColumnID;
	DBID			TableID;
	DBCOLUMNDESC	*oldCD=NULL;
	DBORDINAL		oldlen;
	LPWSTR			pwszTableName;

	m_pTable->MakeTableName(NULL);
	TableID.eKind			= DBKIND_NAME;
	TableID.uName.pwszName	= BuildValidName(m_cMaxTableName+1, m_pTable->GetTableName());
	pwszTableName			= BuildValidName(m_cMaxTableName, m_pTable->GetTableName());
	
	TESTC_(m_hr = m_pTable->CreateTable(0, 0, pwszTableName), S_OK);

	GetColumnDescOnTable(&m_pTable->GetTableID(), &oldCD, &oldlen);
	ColumnID.eKind			= DBKIND_NAME;
	ColumnID.uName.pwszName	= wcsDuplicate(oldCD[0].dbcid.uName.pwszName);
	
	TESTC_(DropColumnAndCheck(&TableID, &ColumnID), DB_E_NOTABLE);

CLEANUP:
	ReleaseColumnDesc(oldCD, oldlen);
	CHECK(m_pTable->DropTable(), S_OK);
	ReleaseDBID(&ColumnID, FALSE);
	ReleaseDBID(&TableID, FALSE);
	PROVIDER_FREE(pwszTableName);
	TRETURN
}
// }}


// {{ TCW_VAR_PROTOTYPE(7)
//*-----------------------------------------------------------------------
// @mfunc *pTableID contains a NULL table name => DB_E_NOTABLE
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCDropColumn::Variation_7()
{
	TBEGIN
	DBID	ColumnID;
	DBID	TableID;

	ColumnID.eKind			= DBKIND_NAME;
	ColumnID.uName.pwszName	= L"Gateway2001";
	TableID.eKind			= DBKIND_NAME;
	TableID.uName.pwszName	= NULL;

	TESTC_(DropColumnAndCheck(&TableID, &ColumnID), DB_E_NOTABLE);

CLEANUP:
	TRETURN
}
// }}


// {{ TCW_VAR_PROTOTYPE(8)
//*-----------------------------------------------------------------------
// @mfunc *pTableID contains an invalid name => DB_E_NOTABLE
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCDropColumn::Variation_8()
{
	TBEGIN
	DBID			ColumnID;
	DBID			TableID;
	size_t			n;

	m_pTable->MakeTableName(NULL);
	n = min(wcslen(m_pwszInvalidTableChars)+wcslen(m_pTable->GetTableName()), m_cMaxTableName);
	TableID.eKind			= DBKIND_NAME;
	TableID.uName.pwszName	= BuildInvalidName(n, m_pTable->GetTableName(), m_pwszInvalidTableChars);
	ColumnID.eKind			= DBKIND_NAME;
	ColumnID.uName.pwszName	= L"foca";
	
	TESTC_(DropColumnAndCheck(&TableID, &ColumnID), DB_E_NOTABLE);

CLEANUP:
	ReleaseDBID(&TableID, FALSE);
	TRETURN
}
// }}


// {{ TCW_VAR_PROTOTYPE(9)
//*-----------------------------------------------------------------------
// @mfunc Maximum length for a column name => S_OK
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCDropColumn::Variation_9()
{
	TBEGIN
	DBID			ColumnID;
	LPWSTR			pwszColumnName;
	DBCOLUMNDESC	*rgColumnDesc	= NULL;
	DBORDINAL		cColumnDesc		= 0;

	DuplicateColumnDesc(m_rgColumnDesc, m_cColumnDesc, &rgColumnDesc);
	cColumnDesc = m_cColumnDesc;
	ReleaseAllColumnPropSets(rgColumnDesc, cColumnDesc);
	m_pTable->MakeTableName(NULL);
	ColumnID.eKind			= DBKIND_NAME;
	ColumnID.uName.pwszName	= pwszColumnName = BuildValidName(m_cMaxColName, L"aaabcdef");
	ReleaseDBID(&rgColumnDesc[0].dbcid, FALSE);
	rgColumnDesc[0].dbcid.eKind			= DBKIND_NAME;
	rgColumnDesc[0].dbcid.uName.pwszName	= pwszColumnName;

	m_pTable->SetBuildColumnDesc(FALSE);
	m_pTable->SetColumnDesc(rgColumnDesc, cColumnDesc);
	TESTC_(m_hr = m_pTable->CreateTable(0, 0), S_OK);

	TESTC_(DropColumnAndCheck(&m_pTable->GetTableID(), &ColumnID), S_OK);

CLEANUP:
	CHECK(m_pTable->DropTable(), S_OK);
	TRETURN
}
// }}


// {{ TCW_VAR_PROTOTYPE(10)
//*-----------------------------------------------------------------------
// @mfunc 1-char-too-long column name => DB_E_NOCOLUMN
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCDropColumn::Variation_10()
{
	TBEGIN
	DBID			ColumnID;
	LPWSTR			pwszColumnName = NULL;
	DBCOLUMNDESC	*rgColumnDesc	= NULL;
	DBORDINAL		cColumnDesc		= 0;

	DuplicateColumnDesc(m_rgColumnDesc, m_cColumnDesc, &rgColumnDesc);
	cColumnDesc = m_cColumnDesc;
	ReleaseAllColumnPropSets(rgColumnDesc, cColumnDesc);
	m_pTable->SetBuildColumnDesc(FALSE);
	m_pTable->SetColumnDesc(rgColumnDesc, cColumnDesc);
	
	m_pTable->MakeTableName(NULL);
	ColumnID.eKind			= DBKIND_NAME;
	ColumnID.uName.pwszName = pwszColumnName = BuildValidName(m_cMaxColName, L"aaabcdef"); 
	ColumnID.uName.pwszName	= BuildValidName(m_cMaxColName+1, m_pTable->GetTableName());
	ReleaseDBID(&rgColumnDesc[0].dbcid, FALSE);
	rgColumnDesc[0].dbcid.eKind				= DBKIND_NAME;
	rgColumnDesc[0].dbcid.uName.pwszName	= pwszColumnName;
	
	TESTC_(m_hr = m_pTable->CreateTable(0, 0), S_OK);

	//NOTE: spec was changed in MDAC 2.6 to replace DB_E_BADCOLUMNID with DB_E_NOCOLUMN 
	//		for ITableDefinition::DropColumn. So when runnning against MDAC 2.5 expect DB_E_BADCOLUMNID
	//      This is for SQL-specific provider. For other providers, you should modify this to test against your target spec
	TESTC_(DropColumnAndCheck(&m_pTable->GetTableID(), &ColumnID), g_fSQLOLEDB25 ? DB_E_BADCOLUMNID : DB_E_NOCOLUMN);

CLEANUP:
	CHECK(m_pTable->DropTable(), S_OK);
	PROVIDER_FREE(ColumnID.uName.pwszName);
	TRETURN
}
// }}


// {{ TCW_VAR_PROTOTYPE(11)
//*-----------------------------------------------------------------------
// @mfunc *pColumnID contains a NULL column name pointer => E_INVALIDARG
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCDropColumn::Variation_11()
{
	TBEGIN
	DBID			ColumnID;

	// create a table, which contains a maximum size table length
	m_pTable->SetBuildColumnDesc(TRUE);
	TESTC_(m_hr = m_pTable->CreateTable(0, 0), S_OK);

	ColumnID.eKind				= DBKIND_NAME;
	ColumnID.uName.pwszName		= NULL;

	//NOTE: spec was changed in MDAC 2.6 to replace DB_E_BADCOLUMNID with DB_E_NOCOLUMN 
	//		for ITableDefinition::DropColumn. So when runnning against MDAC 2.5 expect DB_E_BADCOLUMNID
	//      This is for SQL-specific provider. For other providers, you should modify this to test against your target spec
	TESTC_(DropColumnAndCheck(&m_pTable->GetTableID(), &ColumnID), g_fSQLOLEDB25 ? DB_E_BADCOLUMNID : DB_E_NOCOLUMN);

CLEANUP:
	CHECK(m_pTable->DropTable(), S_OK);
	TRETURN
}
// }}


// {{ TCW_VAR_PROTOTYPE(12)
//*-----------------------------------------------------------------------
// @mfunc *pColumnID contains an invalid column name => E_INVALID ARG
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCDropColumn::Variation_12()
{
	TBEGIN
	DBID			ColumnID;
	LPWSTR			pwszColumnName;
	size_t			n;

	m_pTable->SetBuildColumnDesc(TRUE);
	m_pTable->MakeTableName(NULL);
	n = min(wcslen(m_pTable->GetTableName())+wcslen(m_pwszInvalidColChars), m_cMaxColName);
	pwszColumnName = BuildInvalidName(n, m_pTable->GetTableName(), m_pwszInvalidColChars);
	// create a table, which contains a maximum size table length
	TESTC_(m_hr = m_pTable->CreateTable(0, 0), S_OK);

	ColumnID.eKind			= DBKIND_NAME;
	ColumnID.uName.pwszName	= pwszColumnName;

	//NOTE: spec was changed in MDAC 2.6 to replace DB_E_BADCOLUMNID with DB_E_NOCOLUMN 
	//		for ITableDefinition::DropColumn. So when runnning against MDAC 2.5 expect DB_E_BADCOLUMNID
	//      This is for SQL-specific provider. For other providers, you should modify this to test against your target spec
	TESTC_(DropColumnAndCheck(&m_pTable->GetTableID(), &ColumnID), g_fSQLOLEDB25 ? DB_E_BADCOLUMNID : DB_E_NOCOLUMN);

CLEANUP:
	CHECK(m_pTable->DropTable(), S_OK);
	PROVIDER_FREE(pwszColumnName);
	TRETURN
}
// }}


// {{ TCW_VAR_PROTOTYPE(13)
//*-----------------------------------------------------------------------
// @mfunc Drop all the columns of a table => S_OK
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCDropColumn::Variation_13()
{
	TBEGIN
	HRESULT			hr;
	DBID			ColumnID;
	DBORDINAL		n, cColumns;
	DBCOLUMNDESC	*rgColumnDesc	= NULL;

	m_pTable->SetBuildColumnDesc(TRUE);
	TESTC_(m_hr = m_pTable->CreateTable(0, 0), S_OK);

	//GetColumnInfo(&m_pTable->GetTableID(), &cColumns, &rgColInfo, &pStringBuffer);
	TESTC(GetColumnDescOnTable(&m_pTable->GetTableID(), &rgColumnDesc, &cColumns));
	// check for bookmarks
	n = 0;
	for (; n < cColumns-1; n++)
	{
		// drop column i
		//DuplicateDBID(rgColInfo[n].columnid, &ColumnID);
		DuplicateDBID(rgColumnDesc[n].dbcid, &ColumnID);
		if ( !CHECK(hr = DropColumnAndCheck(&m_pTable->GetTableID(), &ColumnID), 
				S_OK))
		{
			if (DBKIND_NAME == rgColumnDesc[n].dbcid.eKind)
				odtLog << "cannot drop column " << rgColumnDesc[n].dbcid.uName.pwszName << "!\n";
		}
		else if (DBKIND_NAME == rgColumnDesc[n].dbcid.eKind)
			odtLog << "Column "<< rgColumnDesc[n].dbcid.uName.pwszName << " was successfully dropped\n";
		ReleaseDBID(&ColumnID, FALSE);
	}
	// try to drop the last column
	DuplicateDBID(rgColumnDesc[cColumns-1].dbcid, &ColumnID);
	hr = DropColumnAndCheck(&m_pTable->GetTableID(), &ColumnID);
	if (FAILED(hr))
	{
		if (DBKIND_NAME == rgColumnDesc[cColumns-1].dbcid.eKind)
			odtLog << "cannot drop column " << rgColumnDesc[cColumns-1].dbcid.uName.pwszName << " (the last one)!\n";
	}
	else if (DBKIND_NAME == rgColumnDesc[cColumns-1].dbcid.eKind)
		odtLog << "Column "<< rgColumnDesc[cColumns-1].dbcid.uName.pwszName << " (the last column) was successfully dropped\n";
	ReleaseDBID(&ColumnID, FALSE);

CLEANUP:
	CHECK(m_pTable->DropTable(), S_OK);
	//PROVIDER_FREE(rgColInfo);
	//PROVIDER_FREE(pStringBuffer);
	ReleaseColumnDesc(rgColumnDesc, cColumns, TRUE);
	TRETURN
}
// }}


// {{ TCW_VAR_PROTOTYPE(14)
//*-----------------------------------------------------------------------
// @mfunc Try to delete an inexistent column => DB_E_NOCOLUMN
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCDropColumn::Variation_14()
{
	TBEGIN
	DBID			ColumnID;

	m_pTable->SetBuildColumnDesc(TRUE);
	TESTC_(m_hr = m_pTable->CreateTable(0, 0), S_OK);

	ColumnID.eKind				= DBKIND_NAME;
	ColumnID.uName.pwszName		= L"inexistentColumn";

	//NOTE: spec was changed in MDAC 2.6 to replace DB_E_BADCOLUMNID with DB_E_NOCOLUMN 
	//		for ITableDefinition::DropColumn. So when runnning against MDAC 2.5 expect DB_E_BADCOLUMNID
	//      This is for SQL-specific provider. For other providers, you should modify this to test against your target spec
	TESTC_(DropColumnAndCheck(&m_pTable->GetTableID(), &ColumnID), g_fSQLOLEDB25 ? DB_E_BADCOLUMNID : DB_E_NOCOLUMN);

CLEANUP:
	CHECK(m_pTable->DropTable(), S_OK);
	TRETURN
}
// }}


// {{ TCW_VAR_PROTOTYPE(15)
//*-----------------------------------------------------------------------
// @mfunc Table in use => DB_E_TABLEINUSE
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCDropColumn::Variation_15()
{
	TBEGIN
	IRowset			*pIRowset=NULL;
	CCol			col;

	m_pTable->SetRowset((IUnknown**)&pIRowset);
	m_pTable->SetRIID((struct _GUID*)&IID_IRowset);

	m_pTable->SetBuildColumnDesc(TRUE);
	TESTC_(m_hr = m_pTable->CreateTable(0, 0), S_OK);

	m_pTable->AddInfoFromColumnsSchemaRowset(m_pITableDefinition, 
		DBKIND_NAME != m_pTable->GetTableID().eKind? m_pTable->GetTableID().uName.pwszName: NULL);

	col = m_pTable->GetColInfoForUpdate(1);
	TEST2C_(m_hr = DropColumnAndCheck(&m_pTable->GetTableID(), 
		col.GetColID()), S_OK, DB_E_TABLEINUSE);

	odtLog << ((S_OK == m_hr)? "column was dropped\n": "column has been preserved\n");

CLEANUP:
	m_pTable->SetRowset(NULL);
	CHECK(m_pTable->DropTable(), S_OK);
	TRETURN
}
// }}


// {{ TCW_VAR_PROTOTYPE(16)
//*-----------------------------------------------------------------------
// @mfunc Valid name of an inexistent table => DB_E_NOTABLE
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCDropColumn::Variation_16()
{
	TBEGIN
	DBID	ColumnID, TableID;

	m_pTable->MakeTableName(NULL);
	DuplicateDBID(m_rgColumnDesc[0].dbcid, &ColumnID);
	
	TableID.eKind			= DBKIND_NAME;
	TableID.uName.pwszName	= m_pTable->GetTableName();

	//NOTE: spec was changed in MDAC 2.6 to replace DB_E_BADCOLUMNID with DB_E_NOCOLUMN 
	//		for ITableDefinition::DropColumn. So when runnning against MDAC 2.5 expect DB_E_BADCOLUMNID
	//      This is for SQL-specific provider. For other providers, you should modify this to test against your target spec
	TEST2C_(m_hr = DropColumnAndCheck(&TableID, &ColumnID), DB_E_NOTABLE, g_fSQLOLEDB25 ? DB_E_BADCOLUMNID : DB_E_NOCOLUMN);

	ReleaseDBID(&ColumnID, FALSE);
CLEANUP:
	TRETURN
}
// }}


// {{ TCW_VAR_PROTOTYPE(17)
//*-----------------------------------------------------------------------
// @mfunc Abort with retaining
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCDropColumn::Variation_17()
{
	TBEGIN
	ITransactionLocal	*pITransactionLocal = NULL;
	DBCOLUMNDESC		*newCD = NULL, *oldCD = NULL;
	DBORDINAL			newlen = 0, oldlen = 0;
	CCol				col;
	DBORDINAL			nCol;
	VARIANT				vSupportedTxnDDL;

	TESTC_PROVIDER(VerifyInterface(m_pITableDefinition, IID_ITransactionLocal, 
			SESSION_INTERFACE, (IUnknown**)&pITransactionLocal));

	VariantInit(&vSupportedTxnDDL);
	TESTC_PROVIDER(GetProperty(DBPROP_SUPPORTEDTXNDDL, DBPROPSET_DATASOURCEINFO, 
			g_pIDBInitialize, &vSupportedTxnDDL));
	
	TESTC(VT_I4 == vSupportedTxnDDL.vt);
	// what values should we accept?
	TESTC_PROVIDER(DBPROPVAL_TC_NONE != vSupportedTxnDDL.lVal);
		
	// create a table 
	m_pTable->SetBuildColumnDesc(TRUE);
	TESTC_(m_hr = m_pTable->CreateTable(0, 0), S_OK);

	GetColumnDescOnTable(&m_pTable->GetTableID(), &oldCD, &oldlen);

	// start the transaction
	TESTC_(m_hr = StartTransaction(pITransactionLocal), S_OK);

	// try to drop a column from table
	nCol	= (ULONG)rand()%m_pTable->CountColumnsOnTable()+1;
	col		= m_pTable->GetColInfoForUpdate(nCol);

	switch(vSupportedTxnDDL.lVal)
	{
		case DBPROPVAL_TC_DML:
			//check for XACT_E_XTIONEXISTS
			CHECK(m_pITableDefinition->DropColumn(&m_pTable->GetTableID(), 
				col.GetColID()), XACT_E_XTIONEXISTS);
			break;

		case DBPROPVAL_TC_DDL_IGNORE:
			// the statement is not transacted
		case DBPROPVAL_TC_ALL:
		case DBPROPVAL_TC_DDL_COMMIT:
			CHECK(DropColumnAndCheck(&m_pTable->GetTableID(), col.GetColID()), S_OK);
			break;

		case DBPROPVAL_TC_DDL_LOCK:
			CHECK(m_pITableDefinition->DropColumn(&m_pTable->GetTableID(), 
				col.GetColID()), S_OK);
			break;
			
		default:
			TESTC(FALSE);
	}

	// abort retaining
	if (DBPROPVAL_TC_DDL_COMMIT != vSupportedTxnDDL.lVal)
	{
		CHECK(pITransactionLocal->Abort(NULL, TRUE, FALSE), S_OK);
		//check the retaining propriety
		CHECK(m_hr = pITransactionLocal->Abort(NULL, FALSE, FALSE), S_OK);
	}

	GetColumnDescOnTable(&m_pTable->GetTableID(), &newCD, &newlen);
	if (	DBPROPVAL_TC_DDL_IGNORE == vSupportedTxnDDL.lVal
		||	DBPROPVAL_TC_DDL_COMMIT == vSupportedTxnDDL.lVal)
	{	// check column was dropped
		COMPARE(CheckColInfo(newCD, newlen, oldCD, oldlen, &oldCD[nCol-1]), TRUE);
	}
	else
	{	// check column was not dropped
		COMPARE(AreColEqual(oldCD, oldlen, newCD, newlen), TRUE);
	}
	ReleaseColumnDesc(newCD, newlen);

CLEANUP:
	ReleaseColumnDesc(oldCD, oldlen);
	SAFE_RELEASE(pITransactionLocal);
	m_hr = m_pTable->DropTable();
	TRETURN
}
// }}


// {{ TCW_VAR_PROTOTYPE(18)
//*-----------------------------------------------------------------------
// @mfunc Abort without retaining
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCDropColumn::Variation_18()
{
	TBEGIN
	ITransactionLocal	*pITransactionLocal = NULL;
	DBCOLUMNDESC		*newCD = NULL, *oldCD = NULL;
	DBORDINAL			newlen = 0, oldlen = 0;
	CCol				col;
	DBORDINAL			nCol;
	VARIANT				vSupportedTxnDDL;

	TESTC_PROVIDER(VerifyInterface(m_pITableDefinition, IID_ITransactionLocal, 
			SESSION_INTERFACE, (IUnknown**)&pITransactionLocal));
		
	VariantInit(&vSupportedTxnDDL);
	TESTC_PROVIDER(GetProperty(DBPROP_SUPPORTEDTXNDDL, DBPROPSET_DATASOURCEINFO, 
			g_pIDBInitialize, &vSupportedTxnDDL));
	
	TESTC(VT_I4 == vSupportedTxnDDL.vt);
	// what values should we accept?
	TESTC_PROVIDER(DBPROPVAL_TC_NONE != vSupportedTxnDDL.lVal);

	// create a table 
	m_pTable->SetBuildColumnDesc(TRUE);
	TESTC_(m_hr = m_pTable->CreateTable(0, 0), S_OK);

	GetColumnDescOnTable(&m_pTable->GetTableID(), &oldCD, &oldlen);

	// start the transaction
	TESTC_(m_hr = StartTransaction(pITransactionLocal), S_OK);

	// try to drop a column from table
	nCol	= (DBORDINAL)rand()%m_pTable->CountColumnsOnTable()+1;
	col		= m_pTable->GetColInfoForUpdate(nCol);

	switch(vSupportedTxnDDL.lVal)
	{
		case DBPROPVAL_TC_DML:
			//check for XACT_E_XTIONEXISTS
			CHECK(m_pITableDefinition->DropColumn(&m_pTable->GetTableID(), 
				col.GetColID()), XACT_E_XTIONEXISTS);
			break;

		case DBPROPVAL_TC_DDL_IGNORE:
			// the statement is not transacted
		case DBPROPVAL_TC_ALL:
		case DBPROPVAL_TC_DDL_COMMIT:
			CHECK(DropColumnAndCheck(&m_pTable->GetTableID(), col.GetColID()), S_OK);
			break;

		case DBPROPVAL_TC_DDL_LOCK:
			CHECK(m_pITableDefinition->DropColumn(&m_pTable->GetTableID(), 
				col.GetColID()), S_OK);
			break;
			
		default:
			TESTC(FALSE);
	}

	if (DBPROPVAL_TC_DDL_COMMIT != vSupportedTxnDDL.lVal)
	{
		// abort non retaining
		CHECK(m_hr = pITransactionLocal->Abort(NULL, FALSE, FALSE), S_OK);
		//check the non-retaining propriety
		CHECK(pITransactionLocal->Abort(NULL, FALSE, FALSE), 
			SUCCEEDED(m_hr)? XACT_E_NOTRANSACTION: S_OK);
	}

	GetColumnDescOnTable(&m_pTable->GetTableID(), &newCD, &newlen);
	if (	DBPROPVAL_TC_DDL_IGNORE == vSupportedTxnDDL.lVal
		||	DBPROPVAL_TC_DDL_COMMIT == vSupportedTxnDDL.lVal)
	{	// check column was dropped
		COMPARE(CheckColInfo(newCD, newlen, oldCD, oldlen, &oldCD[nCol-1]), TRUE);
	}
	else
	{	// check column was not dropped
		COMPARE(AreColEqual(oldCD, oldlen, newCD, newlen), TRUE);
	}
	ReleaseColumnDesc(newCD, newlen);

CLEANUP:
	ReleaseColumnDesc(oldCD, oldlen);
	SAFE_RELEASE(pITransactionLocal);
	m_hr = m_pTable->DropTable();
	TRETURN
}
// }}


// {{ TCW_VAR_PROTOTYPE(19)
//*-----------------------------------------------------------------------
// @mfunc Commit with retaining
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCDropColumn::Variation_19()
{
	TBEGIN
	ITransactionLocal	*pITransactionLocal = NULL;
	DBCOLUMNDESC		*newCD = NULL, *oldCD = NULL;
	DBORDINAL			newlen = 0, oldlen = 0;
	CCol				col;
	DBORDINAL			nCol;
	VARIANT				vSupportedTxnDDL;

	TESTC_PROVIDER(VerifyInterface(m_pITableDefinition, IID_ITransactionLocal, 
			SESSION_INTERFACE, (IUnknown**)&pITransactionLocal));
		
	VariantInit(&vSupportedTxnDDL);
	TESTC_PROVIDER(GetProperty(DBPROP_SUPPORTEDTXNDDL, DBPROPSET_DATASOURCEINFO, 
			g_pIDBInitialize, &vSupportedTxnDDL));
	
	TESTC(VT_I4 == vSupportedTxnDDL.vt);
	// what values should we accept?
	TESTC_PROVIDER(DBPROPVAL_TC_NONE != vSupportedTxnDDL.lVal);

	// create a table 
	m_pTable->SetBuildColumnDesc(TRUE);
	TESTC_(m_hr = m_pTable->CreateTable(0, 0), S_OK);

	GetColumnDescOnTable(&m_pTable->GetTableID(), &oldCD, &oldlen);

	// start the transaction
	TESTC_(m_hr = StartTransaction(pITransactionLocal), S_OK);

	// try to drop a column from table
	nCol	= (ULONG)rand()%m_pTable->CountColumnsOnTable()+1;
	col		= m_pTable->GetColInfoForUpdate(nCol);

	switch(vSupportedTxnDDL.lVal)
	{
		case DBPROPVAL_TC_DML:
			//check for XACT_E_XTIONEXISTS
			CHECK(m_pITableDefinition->DropColumn(&m_pTable->GetTableID(), 
				col.GetColID()), XACT_E_XTIONEXISTS);
			break;

		case DBPROPVAL_TC_DDL_IGNORE:
			// the statement is not transacted
		case DBPROPVAL_TC_ALL:
		case DBPROPVAL_TC_DDL_COMMIT:
			CHECK(DropColumnAndCheck(&m_pTable->GetTableID(), col.GetColID()), S_OK);
			break;

		case DBPROPVAL_TC_DDL_LOCK:
			CHECK(m_pITableDefinition->DropColumn(&m_pTable->GetTableID(), 
				col.GetColID()), S_OK);
			break;
			
		default:
			TESTC(FALSE);
	}

	// abort retaining
	if (DBPROPVAL_TC_DDL_COMMIT != vSupportedTxnDDL.lVal)
	{
		// commit retaining
		CHECK(pITransactionLocal->Commit(TRUE, 0, 0), S_OK);
		// check retain property
		CHECK(m_hr = pITransactionLocal->Abort(NULL, FALSE, FALSE), S_OK);
	}

	// check column was dropped (oldCD must contains new CD and rgColumnDesc[0])
	GetColumnDescOnTable(&m_pTable->GetTableID(), &newCD, &newlen);
	if (DBPROPVAL_TC_DML == vSupportedTxnDDL.lVal)
	{	// check column was not dropped
		COMPARE(AreColEqual(oldCD, oldlen, newCD, newlen), TRUE);
	}
	else
	{	// check column was dropped
		COMPARE(CheckColInfo(newCD, newlen, oldCD, oldlen, &oldCD[nCol-1]), TRUE);
	}
	ReleaseColumnDesc(newCD, newlen);

CLEANUP:
	ReleaseColumnDesc(oldCD, oldlen);
	m_hr = m_pTable->DropTable();
	SAFE_RELEASE(pITransactionLocal);
	TRETURN
}
// }}


// {{ TCW_VAR_PROTOTYPE(20)
//*-----------------------------------------------------------------------
// @mfunc Commit without retaining
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCDropColumn::Variation_20()
{
	TBEGIN
	ITransactionLocal	*pITransactionLocal = NULL;
	DBCOLUMNDESC		*newCD = NULL, *oldCD = NULL;
	DBORDINAL			newlen = 0, oldlen = 0;
	CCol				col;
	DBORDINAL			nCol;
	VARIANT				vSupportedTxnDDL;

	TESTC_PROVIDER(VerifyInterface(m_pITableDefinition, IID_ITransactionLocal, 
			SESSION_INTERFACE, (IUnknown**)&pITransactionLocal));
		
	VariantInit(&vSupportedTxnDDL);
	TESTC_PROVIDER(GetProperty(DBPROP_SUPPORTEDTXNDDL, DBPROPSET_DATASOURCEINFO, 
			g_pIDBInitialize, &vSupportedTxnDDL));
	
	TESTC(VT_I4 == vSupportedTxnDDL.vt);
	// what values should we accept?
	TESTC_PROVIDER(DBPROPVAL_TC_NONE != vSupportedTxnDDL.lVal);

	// create a table 
	m_pTable->SetBuildColumnDesc(TRUE);
	TESTC_(m_hr = m_pTable->CreateTable(0, 0), S_OK);

	GetColumnDescOnTable(&m_pTable->GetTableID(), &oldCD, &oldlen);
	
	// start the transaction
	TESTC_(m_hr = StartTransaction(pITransactionLocal), S_OK);

	// try to drop a column from table
	nCol = (ULONG)rand()%m_pTable->CountColumnsOnTable()+1;
	col = m_pTable->GetColInfoForUpdate(nCol);

	switch(vSupportedTxnDDL.lVal)
	{
		case DBPROPVAL_TC_DML:
			//check for XACT_E_XTIONEXISTS
			CHECK(m_pITableDefinition->DropColumn(&m_pTable->GetTableID(), 
				col.GetColID()), XACT_E_XTIONEXISTS);
			break;

		case DBPROPVAL_TC_DDL_IGNORE:
			// the statement is not transacted
		case DBPROPVAL_TC_ALL:
		case DBPROPVAL_TC_DDL_COMMIT:
			CHECK(DropColumnAndCheck(&m_pTable->GetTableID(), col.GetColID()), S_OK);
			break;

		case DBPROPVAL_TC_DDL_LOCK:
			CHECK(m_pITableDefinition->DropColumn(&m_pTable->GetTableID(), 
				col.GetColID()), S_OK);
			break;
			
		default:
			TESTC(FALSE);
	}

	if (DBPROPVAL_TC_DDL_COMMIT != vSupportedTxnDDL.lVal)
	{
		// commit without retaining
		CHECK(m_hr = pITransactionLocal->Commit(FALSE, 0, 0), S_OK);
		// check retaining / nont retaining prop
		CHECK(pITransactionLocal->Abort(NULL, FALSE, FALSE), 
			FAILED(m_hr)? S_OK: XACT_E_NOTRANSACTION);
	}

	// check column was dropped (oldCD must contains new CD and rgColumnDesc[0])
	GetColumnDescOnTable(&m_pTable->GetTableID(), &newCD, &newlen);
	if (DBPROPVAL_TC_DML == vSupportedTxnDDL.lVal)
	{	// check column was not dropped
		COMPARE(AreColEqual(oldCD, oldlen, newCD, newlen), TRUE);
	}
	else
	{	// check column was dropped
		COMPARE(CheckColInfo(newCD, newlen, oldCD, oldlen, &oldCD[nCol-1]), TRUE);
	}
	ReleaseColumnDesc(newCD, newlen);

CLEANUP:
	ReleaseColumnDesc(oldCD, oldlen);
	m_hr = m_pTable->DropTable();
	SAFE_RELEASE(pITransactionLocal);
	TRETURN
}
// }}


//----------------------------------------------------------------------
//
// @cmember Thread function for TCDropColumn
//----------------------------------------------------------------------
unsigned TCDropColumn::MyThreadProc(ULONG i)
{
	DBID			ColumnID;
	HRESULT			hr;

	if (i>= nThreads)
		return 0;
	ColumnID.eKind			= DBKIND_NAME;
	ColumnID.uName.pwszName	= m_rgName[i];
	Sleep(0); // switch the context

	hr = m_pITableDefinition->DropColumn(&m_pTable->GetTableID(), &ColumnID);
	Sleep(0); // switch the context

	m_rgResult[i] = hr;
	return 1;
} //TCDropColumn::MyThreadProc


// {{ TCW_VAR_PROTOTYPE(21)
//*-----------------------------------------------------------------------
// @mfunc threads on different columns
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCDropColumn::Variation_21()
{ 
	unsigned		rgIDThread[nThreads];
	HANDLE			hrgThread[nThreads];
	CInParam		rgThreadParam[nThreads];
	BOOL			fTestResult = TEST_FAIL;
	ULONG			i;
	ULONG			newnThreads;
	CCol			col;

	// create nThreads names and init the results
	m_pTable->SetBuildColumnDesc(TRUE);
	TESTC_(m_hr = m_pTable->CreateTable(0, 0), S_OK);
	if (m_cColumnDesc < 2)
	{
		odtLog << "There are too few columns in the table\n";
		goto CLEANUP;
	}
	newnThreads = (nThreads <= (ULONG)m_cColumnDesc) ? nThreads: (ULONG)m_cColumnDesc;
	for (i=0; i< newnThreads; i++)
	{
		m_rgResult[i]	= -1;
		col				= m_pTable->GetColInfoForUpdate(i+1);
		m_rgName[i]		= wcsDuplicate(col.GetColName());
		rgThreadParam[i].pObject = this;
		rgThreadParam[i].i		= i;
	}
	
	// creates a table, build m_rgColumnDesc by it
	for (i=0; i<newnThreads; i++)
	{
		hrgThread[i] = (HANDLE)_beginthreadex(NULL, 0, ThreadProc,
							(void*)&rgThreadParam[i],
							0, 
							&rgIDThread[i]);		// input param
		TESTC(0 != hrgThread[i]);
	}

	WaitForMultipleObjects(newnThreads, (CONST HANDLE*)hrgThread, TRUE, 1000);
	Sleep(1000);
	for (i=0; i< newnThreads; i++)
	{
		CloseHandle(hrgThread[i]);
		SAFE_FREE(m_rgName[i]);
	}

	for (i=0; i<newnThreads; i++)
		TESTC_(m_rgResult[i], S_OK);
	fTestResult = TEST_PASS;

CLEANUP:
	DropTableAndCheck(&m_pTable->GetTableID());
	return fTestResult;
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(22)
//*-----------------------------------------------------------------------
// @mfunc threads on the same column
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCDropColumn::Variation_22()
{ 
	unsigned		rgIDThread[nThreads];
	HANDLE			hrgThread[nThreads];
	CInParam		rgThreadParam[nThreads];
	BOOL			fTestResult = TEST_FAIL;
	ULONG			i, nS_OK, nDB_E_NOCOLUMN;
	CCol			col;
	DBORDINAL		nCol;

	// create n names and init the results
	m_pTable->SetBuildColumnDesc(TRUE);
	TESTC_(m_hr = m_pTable->CreateTable(0, 0), S_OK);
	if (m_cColumnDesc < 1)
	{
		odtLog << "There are too few columns in the table\n";
		goto CLEANUP;
	}
	nCol = (ULONG)rand()%m_pTable->CountColumnsOnTable()+1;
	for (i=0; i< nThreads; i++)
	{
		m_rgResult[i]	= -1;
		col				= m_pTable->GetColInfoForUpdate(nCol);
		m_rgName[i]		= wcsDuplicate(col.GetColName());
		rgThreadParam[i].pObject = this;
		rgThreadParam[i].i		= i;
	}
	
	// creates a table, build m_rgColumnDesc by it
	for (i=0; i<nThreads; i++)
	{
		hrgThread[i] = (HANDLE)_beginthreadex(NULL, 0, ThreadProc,
							(void*)&rgThreadParam[i],
							0, 
							&rgIDThread[i]);		// input param
		TESTC(0 != hrgThread[i]);
	}

	WaitForMultipleObjects(nThreads, (CONST HANDLE*)hrgThread, TRUE, 1000);
	Sleep(1000);
	for (i=0; i< nThreads; i++)
	{
		CloseHandle(hrgThread[i]);
		SAFE_FREE(m_rgName[i]);
	}

	//NOTE: spec was changed in MDAC 2.6 to replace DB_E_BADCOLUMNID with DB_E_NOCOLUMN 
	//		for ITableDefinition::DropColumn. So when runnning against MDAC 2.5 expect DB_E_BADCOLUMNID
	//      This is for SQL-specific provider. For other providers, you should modify this to test against your target spec
	for (i=nS_OK=nDB_E_NOCOLUMN=0; i<nThreads; i++)
	{
		if (m_rgResult[i] == S_OK)
			nS_OK++;
		else if (CHECK(m_rgResult[i], g_fSQLOLEDB25 ? DB_E_BADCOLUMNID : DB_E_NOCOLUMN))
			nDB_E_NOCOLUMN++;
		else 
			goto CLEANUP;
	}
	TESTC(nS_OK == 1 && nDB_E_NOCOLUMN == nThreads-1);
	fTestResult = TEST_PASS;

CLEANUP:
	DropTableAndCheck(&m_pTable->GetTableID());
	return fTestResult;
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(23)
//*-----------------------------------------------------------------------
// @mfunc Drop a column twice => DB_E_NOCOLUMN
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCDropColumn::Variation_23()
{ 
	TBEGIN
	CCol	col;

	m_pTable->SetBuildColumnDesc(TRUE);
	TESTC_(m_hr = m_pTable->CreateTable(0, 0), S_OK);
	
	m_pTable->AddInfoFromColumnsSchemaRowset(m_pITableDefinition, 
		DBKIND_NAME != m_pTable->GetTableID().eKind? m_pTable->GetTableID().uName.pwszName: NULL);

	col = m_pTable->GetColInfoForUpdate((ULONG)rand()%m_pTable->CountColumnsOnTable()+1);
	
	TESTC_(DropColumnAndCheck(&m_pTable->GetTableID(), col.GetColID()), S_OK);

	//NOTE: spec was changed in MDAC 2.6 to replace DB_E_BADCOLUMNID with DB_E_NOCOLUMN 
	//		for ITableDefinition::DropColumn. So when runnning against MDAC 2.5 expect DB_E_BADCOLUMNID
	//      This is for SQL-specific provider. For other providers, you should modify this to test against your target spec
	TESTC_(DropColumnAndCheck(&m_pTable->GetTableID(), col.GetColID()), g_fSQLOLEDB25 ? DB_E_BADCOLUMNID : DB_E_NOCOLUMN);

CLEANUP:
	CHECK(m_pTable->DropTable(), S_OK);
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(24)
//*-----------------------------------------------------------------------
// @mfunc 2 TableDefinition interfaces on the same table, try to drop 2 different columns => S_OK
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCDropColumn::Variation_24()
{ 
	TBEGIN
	ITableDefinition	*pITableDefinition = NULL;
	CCol				col;

	TESTC(VerifyInterface(m_pIOpenRowset, IID_ITableDefinition, SESSION_INTERFACE, (IUnknown**)&pITableDefinition));
	m_pTable->SetBuildColumnDesc(TRUE);
	TESTC_(m_hr = m_pTable->CreateTable(0, 0), S_OK);

	m_pTable->AddInfoFromColumnsSchemaRowset(m_pITableDefinition, 
		DBKIND_NAME != m_pTable->GetTableID().eKind? m_pTable->GetTableID().uName.pwszName: NULL);

	col = m_pTable->GetColInfoForUpdate(1);
	TESTC_(DropColumnAndCheck(&m_pTable->GetTableID(), col.GetColID()),	S_OK);

	col = m_pTable->GetColInfoForUpdate(2);
	TESTC_(DropColumnAndCheck(&m_pTable->GetTableID(), col.GetColID(), pITableDefinition), S_OK);

CLEANUP:
	SAFE_RELEASE(pITableDefinition);
	m_hr = m_pTable->DropTable();
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(25)
//*-----------------------------------------------------------------------
// @mfunc Drop as many column as possible from a table created with a SQL statement
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCDropColumn::Variation_25()
{ 
	TBEGIN
	DBORDINAL			i, cColumns;
	BOOL				fOldTableCreation	= GetModInfo()->UseITableDefinition(FALSE);
	DBCOLUMNDESC		*rgColumnDesc		= NULL;
	IDBCreateCommand	*pIDBCreateCommand	= NULL;
	
	// check whether commands are supported
	TESTC_PROVIDER(VerifyInterface(m_pITableDefinition, IID_IDBCreateCommand,
		SESSION_INTERFACE, (IUnknown**)&pIDBCreateCommand));

	m_pTable->SetBuildColumnDesc(TRUE);
	TESTC_(m_pTable->CreateTable(0, 0), S_OK);
	
	TESTC(GetColumnDescOnTable(&m_pTable->GetTableID(), &rgColumnDesc, &cColumns));

	for (i=0; i<cColumns-1; i++)
	{
		if ( !CHECK(m_hr = DropColumnAndCheck(&m_pTable->GetTableID(), &rgColumnDesc[i].dbcid), S_OK) )
			odtLog << "could not drop the column \n";
	}
	m_hr = DropColumnAndCheck(&m_pTable->GetTableID(), &rgColumnDesc[cColumns-1].dbcid);
	odtLog << ((SUCCEEDED(m_hr)) ? "\tlast column was dropped\n" : "\t could not drop the last column\n");

	CHECK(m_pTable->DropTable(), S_OK);

CLEANUP:
	SAFE_RELEASE(pIDBCreateCommand);
	GetModInfo()->UseITableDefinition(fOldTableCreation);
	ReleaseColumnDesc(rgColumnDesc, cColumns, TRUE);
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(26)
//*-----------------------------------------------------------------------
// @mfunc Drop a column from a 2 column table
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCDropColumn::Variation_26()
{ 
	TBEGIN
	DBCOLUMNDESC	*rgColumnDesc	= NULL;
	ULONG			cColumnDesc		= 2;

	DuplicateColumnDesc(m_rgColumnDesc, cColumnDesc, &rgColumnDesc);
	ReleaseAllColumnPropSets(rgColumnDesc, cColumnDesc);
	m_pTable->SetBuildColumnDesc(FALSE);
	m_pTable->SetColumnDesc(rgColumnDesc, cColumnDesc);
	TESTC_(m_hr = m_pTable->CreateTable(0, 0), S_OK);

	TESTC_(DropColumnAndCheck(&m_pTable->GetTableID(), &rgColumnDesc[0].dbcid), S_OK);

CLEANUP:
	CHECK(m_pTable->DropTable(), S_OK);
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(27)
//*-----------------------------------------------------------------------
// @mfunc drop a column from a 1 column table
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCDropColumn::Variation_27()
{ 
	TBEGIN
	DBCOLUMNDESC	*rgColumnDesc	= NULL;
	ULONG			cColumnDesc		= 1;

	DuplicateColumnDesc(m_rgColumnDesc, cColumnDesc, &rgColumnDesc);
	ReleaseAllColumnPropSets(rgColumnDesc, cColumnDesc);
	m_pTable->SetBuildColumnDesc(FALSE);
	m_pTable->SetColumnDesc(rgColumnDesc, cColumnDesc);
	TESTC_(m_hr = m_pTable->CreateTable(0, 0), S_OK);

	m_hr = DropColumnAndCheck(&m_pTable->GetTableID(), &rgColumnDesc[0].dbcid);
		
	if (S_OK == m_hr)			
		odtLog << "the only column of the table was dropped\n";
	else
		odtLog << "could not drop the only column of the table\n";

CLEANUP:
	CHECK(m_pTable->DropTable(), S_OK);
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(28)
//*-----------------------------------------------------------------------
// @mfunc drop a column from a non empty table => S_OK
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCDropColumn::Variation_28()
{ 
	TBEGIN
	CCol	col;

	m_pTable->SetBuildColumnDesc(TRUE);
	TESTC_(m_hr = m_pTable->CreateTable(10, 0), S_OK);

	m_pTable->AddInfoFromColumnsSchemaRowset(m_pITableDefinition, 
		DBKIND_NAME != m_pTable->GetTableID().eKind? m_pTable->GetTableID().uName.pwszName: NULL);

	col = m_pTable->GetColInfoForUpdate((ULONG)rand()%m_pTable->CountColumnsOnTable()+1);
	TESTC_(DropColumnAndCheck(&m_pTable->GetTableID(), col.GetColID()), S_OK);

CLEANUP:
	CHECK(m_pTable->DropTable(), S_OK);
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(29)
//*-----------------------------------------------------------------------
// @mfunc drop a column from an empty table
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCDropColumn::Variation_29()
{ 
	TBEGIN
	CCol	col;

	m_pTable->SetBuildColumnDesc(TRUE);
	TESTC_(m_hr = m_pTable->CreateTable(0, 0), S_OK);

	m_pTable->AddInfoFromColumnsSchemaRowset(m_pITableDefinition, 
		DBKIND_NAME != m_pTable->GetTableID().eKind? m_pTable->GetTableID().uName.pwszName: NULL);

	col = m_pTable->GetColInfoForUpdate((ULONG)rand()%m_pTable->CountColumnsOnTable()+1);
	TESTC_(DropColumnAndCheck(&m_pTable->GetTableID(), col.GetColID()), S_OK);

CLEANUP:
	CHECK(m_pTable->DropTable(), S_OK);
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(30)
//*-----------------------------------------------------------------------
// @mfunc drop a nullable, an autoincrementable and a default value column
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCDropColumn::Variation_30()
{
	TBEGIN
	DBORDINAL		nAutoInc;
	DBORDINAL		nNull;
	DBORDINAL		nDefault;
	DBORDINAL		i;
	BOOL			fFound = FALSE;
	VARIANT			defVal;
	DBID			ColumnID;
	DBCOLUMNDESC	*rgColumnDesc	= NULL;
	DBORDINAL		cColumnDesc		= 0;
	CCol			col;
	CTable					*pTable = new CTable(m_pThisTestModule->m_pIUnknown2, (LPWSTR)gwszModuleName);
	CList<WCHAR *,WCHAR *>	NativeTypesList;
	CList<DBTYPE,DBTYPE>	ProviderTypesList;

	TESTC_PROVIDER(SettableProperty(DBPROP_COL_NULLABLE, DBPROPSET_COLUMN));
	TESTC_PROVIDER(SettableProperty(DBPROP_COL_AUTOINCREMENT, DBPROPSET_COLUMN));
	TESTC_PROVIDER(SettableProperty(DBPROP_COL_DEFAULT, DBPROPSET_COLUMN));

	pTable->CreateTypeColInfo(NativeTypesList, ProviderTypesList);
	DuplicateColumnDesc(m_rgColumnDesc, m_cColumnDesc, &rgColumnDesc);
	cColumnDesc = m_cColumnDesc;
	ReleaseAllColumnPropSets(rgColumnDesc, cColumnDesc);

	// get an autoincrementable column
	nAutoInc = cColumnDesc;
	for (i=0; i < cColumnDesc && !fFound; i++)
	{	
		col = GetType(GetColumnTypeName(&rgColumnDesc[i]), rgColumnDesc[i].wType);
		if (TRUE == (fFound = col.CanAutoInc()))
			nAutoInc = i;
	}

	TESTC(nAutoInc < cColumnDesc);

	// get the nullable and default columns
	nNull		= (nAutoInc+1) % cColumnDesc;
	nDefault	= (nAutoInc+2) % cColumnDesc;
	
	// set autoincrementable property on a column
	SetProperty(&rgColumnDesc[nAutoInc].rgPropertySets, &rgColumnDesc[nAutoInc].cPropertySets, 
		DBPROP_COL_AUTOINCREMENT, VT_BOOL, (LPVOID)VARIANT_TRUE, DBPROPOPTIONS_REQUIRED);

	// set nullable property on a column (also add default for it)
	SetProperty(&rgColumnDesc[nNull].rgPropertySets, &rgColumnDesc[nNull].cPropertySets, 
		DBPROP_COL_NULLABLE, VT_BOOL, (LPVOID)VARIANT_TRUE, DBPROPOPTIONS_REQUIRED);

	VariantInit(&defVal);
	GetDefaultValue(&rgColumnDesc[nNull], &defVal, pTable);
	SetDefaultProperty(&rgColumnDesc[nNull].rgPropertySets, &rgColumnDesc[nNull].cPropertySets,
		&defVal, DBPROPOPTIONS_REQUIRED);	// might be not supported
	VariantClear(&defVal);
	// set default column
	GetDefaultValue(&rgColumnDesc[nDefault], &defVal, pTable);
	SetDefaultProperty(&rgColumnDesc[nDefault].rgPropertySets, &rgColumnDesc[nDefault].cPropertySets,
		&defVal, DBPROPOPTIONS_REQUIRED);	// might be not supported
	VariantClear(&defVal);

	// create the table with a autoinc column, a nullable one and a default one
	m_pTable->SetBuildColumnDesc(FALSE);
	m_pTable->SetColumnDesc(rgColumnDesc, cColumnDesc);
	TESTC_(m_hr = m_pTable->CreateTable(0, 0), S_OK);

	DuplicateDBID(rgColumnDesc[nAutoInc].dbcid, &ColumnID);
	m_hr = DropColumnAndCheck(&m_pTable->GetTableID(), &ColumnID);
	if (S_OK != m_hr)
		odtLog << "could not drop the autoincrementable column\n";
	else
		odtLog << "the autoincrementable column was dropped \n";
	ReleaseDBID(&ColumnID, FALSE);

	DuplicateDBID(rgColumnDesc[nNull].dbcid, &ColumnID);
	m_hr = DropColumnAndCheck(&m_pTable->GetTableID(), &ColumnID);
	if (S_OK != m_hr)
		odtLog << "could not drop the nullable column\n";
	else
		odtLog << "the nullable column was dropped \n";
	ReleaseDBID(&ColumnID, FALSE);

	DuplicateDBID(m_rgColumnDesc[nDefault].dbcid, &ColumnID);
	m_hr = DropColumnAndCheck(&m_pTable->GetTableID(), &ColumnID);
	if (S_OK != m_hr)
		odtLog << "could not drop the default value column\n";
	else
		odtLog << "the default value column was dropped \n";
	ReleaseDBID(&ColumnID, FALSE);
	CHECK(m_pTable->DropTable(), S_OK);

CLEANUP:
	delete pTable;
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(31)
//*-----------------------------------------------------------------------
// @mfunc try to drop a column from a view
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCDropColumn::Variation_31()
{ 
	TBEGIN
	LPWSTR			pwszViewName = L"HagiView";	// just a view name
	DBID			TableID;
	CCol			col;
	IDBCreateCommand	*pIDBCreateCommand	= NULL;

	// check whether commands are supported
	TESTC_PROVIDER(VerifyInterface(m_pITableDefinition, IID_IDBCreateCommand,
		SESSION_INTERFACE, (IUnknown**)&pIDBCreateCommand));

	m_pTable->SetBuildColumnDesc(TRUE);
	TESTC_(m_hr = m_pTable->CreateTable(0, 0), S_OK);
	m_pTable->AddInfoFromColumnsSchemaRowset(m_pITableDefinition, m_pTable->GetTableName());

	// create the view
	m_pTable->SetViewName(pwszViewName);
	if ( S_OK != (m_hr = m_pTable->ExecuteCommand(
						CREATE_VIEW,
						IID_NULL,
						pwszViewName,						// the table name will be the implicit one
						NULL,						// don't return the command statement
						0, 
						NULL,
						EXECUTE_IFNOERROR			// execute the command
						)) 
		)
	{
		odtLog << "\t the view cannot be created\n";
		goto CLEANUP;
	}

	TESTC_(m_hr, S_OK);

	// try to drop a column from the view
	TableID.eKind			= DBKIND_NAME;
	TableID.uName.pwszName	= L"HagiTable";
	col = m_pTable->GetColInfoForUpdate((ULONG)rand()%m_pTable->CountColumnsOnTable()+1);
	m_hr = DropColumnAndCheck(&TableID, col.GetColID());
	odtLog << ((S_OK == m_hr) ? "column was dropped from view\n" : "could not drop column from view\n");

CLEANUP:
	SAFE_RELEASE(pIDBCreateCommand);
	// drop the view!
	if (m_pTable->GetTableName())
		m_hr = m_pTable->ExecuteCommand(
						DROP_VIEW,
						IID_NULL,
						pwszViewName,						// the table name will be the implicit one
						NULL,						// don't return the command statement
						0, 
						NULL,
						EXECUTE_IFNOERROR			// execute the command
						);
	CHECK(m_hr = m_pTable->DropTable(), S_OK);
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(32)
//*-----------------------------------------------------------------------
// @mfunc drop a column added with an alter table command => S_OK
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCDropColumn::Variation_32()
{ 
	TBEGIN
	DBID			ColumnID;
	LPWSTR			pwszColumnName = L"intHagi";	// the name of the integer column
	LPWSTR			pwszColNameAndType = NULL;
	IDBCreateCommand	*pIDBCreateCommand	= NULL;

	// check whether commands are supported
	TESTC_PROVIDER(VerifyInterface(m_pITableDefinition, IID_IDBCreateCommand,
		SESSION_INTERFACE, (IUnknown**)&pIDBCreateCommand));

	TESTC(NULL != m_rgColumnDesc[0].pwszTypeName);	// it should be a numeric type
	m_pTable->SetBuildColumnDesc(TRUE);
	TESTC_(m_hr = m_pTable->CreateTable(0, 0), S_OK);
	
	// build the column name and type argument of the command
	SAFE_ALLOC(pwszColNameAndType, WCHAR, wcslen(pwszColumnName)+wcslen(m_rgColumnDesc[0].pwszTypeName)+2);
	wcscpy(pwszColNameAndType, pwszColumnName);
	wcscat(pwszColNameAndType, L" ");
	wcscat(pwszColNameAndType, m_rgColumnDesc[0].pwszTypeName);

	// create the ALTER SQL statement
	if ( S_OK != (m_hr = m_pTable->ExecuteCommand(
						ALTER_TABLE_ADD,
						IID_NULL,
						pwszColNameAndType,				// the table name will be the implicit one
						NULL,						// don't return the command statement
						0, 
						NULL,
						EXECUTE_IFNOERROR			// execute the command
						)) 
		)
	{
		odtLog << "Could not add a column in the table, using commands\n";
		goto CLEANUP;
	}

	// try to drop the new column from the table
	ColumnID.eKind			= DBKIND_NAME;
	ColumnID.uName.pwszName	= pwszColumnName;
	TESTC_(DropColumnAndCheck(&m_pTable->GetTableID(), &ColumnID), S_OK);
		
CLEANUP:
	SAFE_RELEASE(pIDBCreateCommand);
	SAFE_FREE(pwszColNameAndType);
	CHECK(m_pTable->DropTable(), S_OK);
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(33)
//*-----------------------------------------------------------------------
// @mfunc try to drop columns using different DBKIND pattern
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCDropColumn::Variation_33()
{ 
	TBEGIN
	DBID			ColumnID;
	CCol			col;

	m_pTable->SetBuildColumnDesc(TRUE);
	TESTC_(m_hr = m_pTable->CreateTable(0, 0), S_OK);

	// try to drop a column
	col = m_pTable->GetColInfoForUpdate(2);
	ColumnID.eKind			= DBKIND_NAME;
	ColumnID.uName.pwszName	= wcsDuplicate(col.GetColName());
	if (m_cColumnDesc > 2)
	{
		CHECK(DropColumnAndCheck(&m_pTable->GetTableID(), &ColumnID), S_OK);
	}
	else
	{
		odtLog << "too few columns, skipped the drop column given by name case \n";
	}
	ReleaseDBID(&ColumnID, FALSE);

	col = m_pTable->GetColInfoForUpdate(4);
	ColumnID.eKind			= DBKIND_GUID;
	memset(&ColumnID.uGuid.guid, 0, sizeof(GUID));

	//NOTE: spec was changed in MDAC 2.6 to replace DB_E_BADCOLUMNID with DB_E_NOCOLUMN 
	//		for ITableDefinition::DropColumn. So when runnning against MDAC 2.5 expect DB_E_BADCOLUMNID
	//      This is for SQL-specific provider. For other providers, you should modify this to test against your target spec
	if (!CHECK(DropColumnAndCheck(&m_pTable->GetTableID(), &ColumnID), g_fSQLOLEDB25 ? DB_E_BADCOLUMNID : DB_E_NOCOLUMN))
	{
		odtLog << "error at the guid case\n";
	}
	
	col = m_pTable->GetColInfoForUpdate(3);
	ColumnID.eKind			= DBKIND_GUID_NAME;
	ColumnID.uGuid.guid		= guidModule;
	ColumnID.uName.pwszName	= col.GetColName();
	m_hr = DropColumnAndCheck(&m_pTable->GetTableID(), &ColumnID);
	if (!CHECK(m_hr, g_fSQLOLEDB25 ? DB_E_BADCOLUMNID : DB_E_NOCOLUMN))
	{
		odtLog << "error at the guid name case\n";
	}
	
	ColumnID.eKind			= DBKIND_GUID_PROPID;
	memset(&ColumnID.uGuid.guid, 0, sizeof(GUID));
	ColumnID.uName.ulPropid	= 0L;
	m_hr = DropColumnAndCheck(&m_pTable->GetTableID(), &ColumnID);
	if (!CHECK(m_hr, g_fSQLOLEDB25 ? DB_E_BADCOLUMNID : DB_E_NOCOLUMN) )
	{
		odtLog << "error at the guid propid case\n";
	}
	
	ColumnID.eKind			= DBKIND_PGUID_NAME;
	ColumnID.uGuid.pguid	= &guidModule;
	ColumnID.uName.pwszName	= NULL;
	m_hr = DropColumnAndCheck(&m_pTable->GetTableID(), &ColumnID);
	if (!CHECK(m_hr, g_fSQLOLEDB25 ? DB_E_BADCOLUMNID : DB_E_NOCOLUMN))
	{
		odtLog << "error at the pguid name case\n";
	}
	
	ColumnID.eKind			= DBKIND_PGUID_PROPID;
	ColumnID.uGuid.pguid	= &guidModule;
	ColumnID.uName.ulPropid	= 0L;
	m_hr = DropColumnAndCheck(&m_pTable->GetTableID(), &ColumnID);
	if (!CHECK(m_hr, g_fSQLOLEDB25 ? DB_E_BADCOLUMNID : DB_E_NOCOLUMN) )
	{
		odtLog << "error at the pguid propid case\n";
	}
	
	ColumnID.eKind			= DBKIND_PROPID;
	ColumnID.uName.ulPropid	= 0L;
	m_hr = DropColumnAndCheck(&m_pTable->GetTableID(), &ColumnID);
	if (!CHECK(m_hr, g_fSQLOLEDB25 ? DB_E_BADCOLUMNID : DB_E_NOCOLUMN))
	{
		odtLog << "error at the propid case\n";
	}
	
	ColumnID.eKind			= 0xff;
	m_hr = DropColumnAndCheck(&m_pTable->GetTableID(), &ColumnID);
	if (!CHECK(m_hr, g_fSQLOLEDB25 ? DB_E_BADCOLUMNID : DB_E_NOCOLUMN))
	{
		odtLog << "error at the inexistent value for eKind case\n";
	}

CLEANUP:
	CHECK(m_hr = m_pTable->DropTable(), S_OK);
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(34)
//*-----------------------------------------------------------------------
// @mfunc Fully Qualified Table Name
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCDropColumn::Variation_34()
{ 
	TBEGIN
	DBID		TableID;
	WCHAR		*pwszQualTableName = NULL;
	WCHAR		*pwszCatalogName = NULL;
	WCHAR		*pwszSchemaName = NULL;
	WCHAR		*pwszTableName = NULL;
	CCol		col;

	// create a regular table
	TESTC(NULL != m_pTable);
	m_pTable->SetBuildColumnDesc(TRUE);
	TESTC_(m_pTable->CreateTable(0, 0), S_OK);
	pwszTableName = m_pTable->GetTableName();
	TableID.eKind = DBKIND_NAME;

	TESTC(GetCatalogSchemaNames(pwszTableName, &pwszCatalogName, &pwszSchemaName));

	//Construct a fully Qualified TableName...
	TESTC_(m_pTable->GetQualifiedName(pwszCatalogName, pwszSchemaName, pwszTableName, &pwszQualTableName),S_OK);
	TableID.uName.pwszName = pwszQualTableName;

	m_pTable->AddInfoFromColumnsSchemaRowset(m_pITableDefinition, 
		DBKIND_NAME != m_pTable->GetTableID().eKind? m_pTable->GetTableID().uName.pwszName: NULL);
	col = m_pTable->GetColInfoForUpdate(1);

	TESTC_(DropColumnAndCheck(&TableID, col.GetColID(), NULL, &m_pTable->GetTableID()), S_OK);
    
CLEANUP:
	m_pTable->DropTable();
	SAFE_FREE(pwszCatalogName);
	SAFE_FREE(pwszSchemaName);
	SAFE_FREE(pwszQualTableName);
    TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(35)
//*-----------------------------------------------------------------------
// @mfunc Quoted Table Name
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCDropColumn::Variation_35()
{ 
	TBEGIN
	DBID	TableID;
	CCol	col;
	
	TableID.eKind = DBKIND_NAME;
	TableID.uName.pwszName = NULL;
	TESTC(NULL != m_pTable);
	TESTC_(m_pTable->CreateTable(0, 0), S_OK);

	m_pTable->GetQuotedName(m_pTable->GetTableName(), &TableID.uName.pwszName);

	m_pTable->AddInfoFromColumnsSchemaRowset(m_pITableDefinition, 
		DBKIND_NAME != m_pTable->GetTableID().eKind? m_pTable->GetTableID().uName.pwszName: NULL);
	col = m_pTable->GetColInfoForUpdate(1);

	TESTC_(DropColumnAndCheck(&TableID, col.GetColID()), S_OK);

CLEANUP:
	m_pTable->DropTable();
	ReleaseDBID(&TableID, FALSE);
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END


// {{ TCW_TERMINATE_METHOD
//--------------------------------------------------------------------
// @mfunc TestCase Termination Routine
//
// @rdesc TRUE or FALSE
//
BOOL TCDropColumn::Terminate()
{
	// TO DO:  Add your own code here

	// {{ TCW_TERM_BASECLASS_CHECK2
	return(TCITableDefinition::Terminate());
}	// }}
// }}
// }}




// {{ TCW_TC_PROTOTYPE(TCDropTable)
//*-----------------------------------------------------------------------
//| Test Case:		TCDropTable - Test Case fo dropping a table
//|	Created:			09/11/97
//*-----------------------------------------------------------------------

//--------------------------------------------------------------------
// @mfunc TestCase Initialization Routine
//
// @rdesc TRUE or FALSE
//
BOOL TCDropTable::Init()
{
	// {{ TCW_INIT_BASECLASS_CHECK
	if(TCITableDefinition::Init())
	// }}
	{
		// TO DO:  Add your own code here
		return TRUE;
	}
	return FALSE;
}


// {{ TCW_VAR_PROTOTYPE(1)
//*-----------------------------------------------------------------------
// @mfunc pTableID is NULL => E_INVALIDARG
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCDropTable::Variation_1()
{

	if ( !CHECK(m_hr = m_pITableDefinition->DropTable(NULL), E_INVALIDARG))
		return TEST_FAIL;
	else
		return TEST_PASS;
}
// }}


// {{ TCW_VAR_PROTOTYPE(2)
//*-----------------------------------------------------------------------
// @mfunc *pTableID is DB_NULLID => DB_E_NOTABLE
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCDropTable::Variation_2()
{
	DBID	TableID;

	TableID = DB_NULLID;
	if ( !CHECK(m_hr = m_pITableDefinition->DropTable(&TableID), DB_E_NOTABLE))
		return TEST_FAIL;
	else
		return TEST_PASS;
}
// }}


// {{ TCW_VAR_PROTOTYPE(3)
//*-----------------------------------------------------------------------
// @mfunc Maximum length for table name => S_OK
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCDropTable::Variation_3()
{
	BOOL	fTestRes = TEST_FAIL;
	WCHAR*	pwszTableName = NULL; 
	DBID	TableID;

	// create a maximum size table name 
	m_pTable->MakeTableName(NULL);
	GetLiteralInfo();
	pwszTableName = BuildValidName(m_cMaxTableName, m_pTable->GetTableName());
	odtLog << "king size table name: " << pwszTableName << ", i.e." << (wcslen(pwszTableName)) << " characters\n";
	m_pTable->SetBuildColumnDesc(TRUE);
	TESTC_(m_hr = m_pTable->CreateTable(0, 0, pwszTableName), S_OK);
	
	TableID.eKind = DBKIND_NAME;
	TableID.uName.pwszName = pwszTableName;
	TESTC_(m_hr = m_pITableDefinition->DropTable(&TableID), S_OK);
	fTestRes = TEST_PASS;

CLEANUP:
	m_pTable->DropTable();
	PROVIDER_FREE(pwszTableName);
	return fTestRes;
}
// }}


// {{ TCW_VAR_PROTOTYPE(4)
//*-----------------------------------------------------------------------
// @mfunc 1-char-too-long table name => DB_E_NOTABLE
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCDropTable::Variation_4()
{
	BOOL	fTestRes = TEST_FAIL;
	WCHAR*	pwszTableName = NULL, *pwszTableName1 = NULL; 
	DBID	TableID;

	// create a maximum size table name 
	m_pTable->MakeTableName(NULL);
	GetLiteralInfo();
	pwszTableName	= BuildValidName(m_cMaxTableName, m_pTable->GetTableName());
	pwszTableName1	= BuildValidName(m_cMaxTableName+1, m_pTable->GetTableName());
	odtLog	<< "1 char too long table name: " << pwszTableName1 << ", i.e." 
			<< wcslen(pwszTableName1) << " characters\n";
	m_pTable->SetBuildColumnDesc(TRUE);
	TESTC_(m_hr = m_pTable->CreateTable(0, 0, pwszTableName), S_OK);

	TableID.eKind = DBKIND_NAME;
	TableID.uName.pwszName = pwszTableName1;
	TESTC_(m_hr = m_pITableDefinition->DropTable(&TableID), DB_E_NOTABLE);
	fTestRes = TEST_PASS;

CLEANUP:
	CHECK(m_pTable->DropTable(), S_OK);
	PROVIDER_FREE(pwszTableName);
	PROVIDER_FREE(pwszTableName1);
	m_pTable->DropTable();
	return fTestRes;
}
// }}


// {{ TCW_VAR_PROTOTYPE(5)
//*-----------------------------------------------------------------------
// @mfunc The pointer to the table name is NULL => DB_E_NOTABLE
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCDropTable::Variation_5()
{
	DBID	TableID;

	TableID.eKind = DBKIND_NAME;
	TableID.uName.pwszName = NULL;
	if ( !CHECK(m_hr = m_pITableDefinition->DropTable(&TableID), DB_E_NOTABLE))
		return TEST_FAIL;
	else
		return TEST_PASS;
}
// }}


// {{ TCW_VAR_PROTOTYPE(6)
//*-----------------------------------------------------------------------
// @mfunc Table name is empty => DB_E_NOTABLE
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCDropTable::Variation_6()
{
	DBID	TableID;

	TableID.eKind = DBKIND_NAME;
	TableID.uName.pwszName = L"";
	if ( !CHECK(m_hr = m_pITableDefinition->DropTable(&TableID), DB_E_NOTABLE))
		return TEST_FAIL;
	else
		return TEST_PASS;
}
// }}


// {{ TCW_VAR_PROTOTYPE(7)
//*-----------------------------------------------------------------------
// @mfunc Invalid table name => DB_E_NOTABLE
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCDropTable::Variation_7()
{
	BOOL	fTestRes = TEST_FAIL;
	WCHAR*	pwszTableName = NULL; 
	size_t	m;
	DBID	TableID;

	// create an invalid table name 
	m_pTable->MakeTableName(NULL);
	GetLiteralInfo();
	m = min(wcslen(m_pTable->GetTableName())+5, m_cMaxTableName);
	pwszTableName = BuildInvalidName(m, m_pTable->GetTableName(), m_pwszInvalidTableChars);
	odtLog << "invalid table name: " << pwszTableName << ", i.e." << wcslen(pwszTableName) << " characters\n";

	TableID.eKind = DBKIND_NAME;
	TableID.uName.pwszName = pwszTableName;

	TESTC_(m_hr = m_pITableDefinition->DropTable(&TableID), DB_E_NOTABLE);
	fTestRes = TEST_PASS;

CLEANUP:
	PROVIDER_FREE(pwszTableName);
	return fTestRes;
}
// }}


// {{ TCW_VAR_PROTOTYPE(8)
//*-----------------------------------------------------------------------
// @mfunc A rowset is opened on table => DB_E_TABLEINUSE
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCDropTable::Variation_8()
{
	BOOL		fTestRes = TEST_FAIL, fExists;
	IRowset*	pIRowset = NULL;
	
	m_pTable->SetBuildColumnDesc(TRUE);
	TESTC_(m_pTable->CreateTable(0, 0), S_OK);
	TESTC_(m_pIOpenRowset->OpenRowset(NULL, &m_pTable->GetTableID(), NULL, IID_IRowset, 
		0, NULL, (IUnknown**)&pIRowset), S_OK);

	fTestRes = TEST_PASS;
	//try to drop the table
	m_hr = m_pITableDefinition->DropTable(&m_pTable->GetTableID());
	if (DB_E_TABLEINUSE != m_hr && !CHECK(m_hr, S_OK))
	{
		odtLog << "The table was dropped, though in use \n";
		fTestRes = TEST_FAIL;
	}
	else
	{
		odtLog << ((DB_E_TABLEINUSE == m_hr) ? "DB_E_TABLEINUSE returned\n": "S_OK returned\n");

		//check the table still exist
		if (!CHECK(m_pTable->DoesTableExist(&m_pTable->GetTableID(), &fExists), S_OK) || 
			(fExists==(S_OK == m_hr)))
			fTestRes = TEST_FAIL;
	}

CLEANUP:
	SAFE_RELEASE(pIRowset);
	m_pTable->DropTable();
	return fTestRes;
}
// }}


// {{ TCW_VAR_PROTOTYPE(9)
//*-----------------------------------------------------------------------
// @mfunc Table in use => DB_E_TABLEINUSE
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCDropTable::Variation_9()
{
	BOOL		fTestRes = TEST_FAIL, fExists;
	IRowset*	pIRowset = NULL;
	
	m_pTable->SetRIID((struct _GUID*)&IID_IRowset);
	m_pTable->SetRowset((IUnknown**)&pIRowset);
	m_pTable->SetBuildColumnDesc(TRUE);
	TESTC_(m_pTable->CreateTable(10, 1), S_OK);
	fTestRes = TEST_PASS;

	//try to release drop the table
	m_hr = m_pITableDefinition->DropTable(&m_pTable->GetTableID());
	if (DB_E_TABLEINUSE != m_hr && S_OK != m_hr)
	{
		odtLog << "The table was dropped, though in use \n";
		fTestRes = TEST_FAIL;
	}
	else
	{
		odtLog << ((DB_E_TABLEINUSE == m_hr) ? "DB_E_TABLEINUSE returned\n" : "S_OK returned\n");

		//check the table still exist
		if (!CHECK(m_pTable->DoesTableExist(&m_pTable->GetTableID(), &fExists), S_OK) || (fExists==(S_OK == m_hr)))
			fTestRes = TEST_FAIL;
	}

CLEANUP:
	m_pTable->SetRowset(NULL);
	m_pTable->DropTable();
	return fTestRes;
}
// }}


// {{ TCW_VAR_PROTOTYPE(10)
//*-----------------------------------------------------------------------
// @mfunc Inexistent table => DB_E_NOTABLE
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCDropTable::Variation_10()
{
	WCHAR*	pwszTableName = NULL; 
	DBID	TableID;

	// create a new valid table name 
	m_pTable->MakeTableName(NULL);
	pwszTableName = m_pTable->GetTableName();
	TableID.eKind = DBKIND_NAME;
	TableID.uName.pwszName = pwszTableName;
	if (!CHECK(m_hr = m_pITableDefinition->DropTable(&TableID), DB_E_NOTABLE))
		return TEST_FAIL;
	else
		return TEST_PASS;
}
// }}


// {{ TCW_VAR_PROTOTYPE(11)
//*-----------------------------------------------------------------------
// @mfunc Abort with retaining
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCDropTable::Variation_11()
{
	TBEGIN
	BOOL				fExists;
	ITransactionLocal	*pITransactionLocal = NULL;
	VARIANT				vSupportedTxnDDL;

	TESTC_PROVIDER(VerifyInterface(m_pITableDefinition, IID_ITransactionLocal,
				SESSION_INTERFACE, (IUnknown**)&pITransactionLocal));

	VariantInit(&vSupportedTxnDDL);
	TESTC_PROVIDER(GetProperty(DBPROP_SUPPORTEDTXNDDL, DBPROPSET_DATASOURCEINFO, 
			g_pIDBInitialize, &vSupportedTxnDDL));
	
	TESTC(VT_I4 == vSupportedTxnDDL.vt);
	// what values should we accept?
	TESTC_PROVIDER(DBPROPVAL_TC_NONE != vSupportedTxnDDL.lVal);

	m_pTable->SetBuildColumnDesc(TRUE);
	TESTC_(m_hr = m_pTable->CreateTable(0,0), S_OK);

	TESTC_(m_hr = StartTransaction(pITransactionLocal), S_OK);

	switch(vSupportedTxnDDL.lVal)
	{
		case DBPROPVAL_TC_DML:
			//check for XACT_E_XTIONEXISTS
				CHECK(m_hr = m_pITableDefinition->DropTable(&m_pTable->GetTableID()), XACT_E_XTIONEXISTS);
			break;

		case DBPROPVAL_TC_DDL_IGNORE:
			// the statement is not transacted
		case DBPROPVAL_TC_ALL:
		case DBPROPVAL_TC_DDL_COMMIT:
			CHECK(DropTableAndCheck(&m_pTable->GetTableID()), S_OK);
			break;

		case DBPROPVAL_TC_DDL_LOCK:
			// error should be returned on further table access
			TESTC_(DropTableAndCheck(&m_pTable->GetTableID()), S_OK);
			break;
			
		default:
			TESTC(FALSE);
	}

	if (DBPROPVAL_TC_DDL_COMMIT != vSupportedTxnDDL.lVal)
	{
		// abort retaining
		CHECK(m_hr = pITransactionLocal->Abort(NULL, TRUE, FALSE), S_OK);
		// check retaining
		CHECK(m_hr = pITransactionLocal->Abort(NULL, FALSE, FALSE), S_OK);
	}

	// check table existence
	CHECK(m_hr = m_pTable->DoesTableExist(&m_pTable->GetTableID(), &fExists), S_OK);
	COMPARE(fExists, DBPROPVAL_TC_DDL_IGNORE != vSupportedTxnDDL.lVal
		&& DBPROPVAL_TC_DDL_COMMIT != vSupportedTxnDDL.lVal);

CLEANUP:
	SAFE_RELEASE(pITransactionLocal);
	m_pTable->DropTable();
	TRETURN
}
// }}


// {{ TCW_VAR_PROTOTYPE(12)
//*-----------------------------------------------------------------------
// @mfunc Abort without retaining
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCDropTable::Variation_12()
{
	TBEGIN
	BOOL				fExists;
	ITransactionLocal	*pITransactionLocal = NULL;
	VARIANT				vSupportedTxnDDL;

	TESTC_PROVIDER(VerifyInterface(m_pITableDefinition, IID_ITransactionLocal,
				SESSION_INTERFACE, (IUnknown**)&pITransactionLocal));

	VariantInit(&vSupportedTxnDDL);
	TESTC_PROVIDER(GetProperty(DBPROP_SUPPORTEDTXNDDL, DBPROPSET_DATASOURCEINFO, 
			g_pIDBInitialize, &vSupportedTxnDDL));
	
	TESTC(VT_I4 == vSupportedTxnDDL.vt);
	// what values should we accept?
	TESTC_PROVIDER(DBPROPVAL_TC_NONE != vSupportedTxnDDL.lVal);

	m_pTable->SetBuildColumnDesc(TRUE);
	TESTC_(m_hr = m_pTable->CreateTable(0,0), S_OK);

	TESTC_(m_hr = StartTransaction(pITransactionLocal), S_OK);

	switch(vSupportedTxnDDL.lVal)
	{
		case DBPROPVAL_TC_DML:
			//check for XACT_E_XTIONEXISTS
				CHECK(m_hr = m_pITableDefinition->DropTable(&m_pTable->GetTableID()), XACT_E_XTIONEXISTS);
			break;

		case DBPROPVAL_TC_DDL_IGNORE:
			// the statement is not transacted
		case DBPROPVAL_TC_ALL:
		case DBPROPVAL_TC_DDL_COMMIT:
			TESTC_(DropTableAndCheck(&m_pTable->GetTableID()), S_OK);
			break;

		case DBPROPVAL_TC_DDL_LOCK:
			// error should be returned on further table operations
			TESTC_(DropTableAndCheck(&m_pTable->GetTableID()), S_OK);
			break;
			
		default:
			TESTC(FALSE);
	}

	if (DBPROPVAL_TC_DDL_COMMIT != vSupportedTxnDDL.lVal)
	{
		// abort non retaining
		CHECK(m_hr = pITransactionLocal->Abort(NULL, FALSE, FALSE), S_OK);
		// check not retaining
		CHECK(pITransactionLocal->Abort(NULL, FALSE, FALSE), 
			FAILED(m_hr)? S_OK : XACT_E_NOTRANSACTION);
	}

	// check table existence
	CHECK(m_hr = m_pTable->DoesTableExist(&m_pTable->GetTableID(), &fExists), S_OK);
	COMPARE(fExists, DBPROPVAL_TC_DDL_IGNORE != vSupportedTxnDDL.lVal
		&& DBPROPVAL_TC_DDL_COMMIT != vSupportedTxnDDL.lVal);

CLEANUP:
	SAFE_RELEASE(pITransactionLocal);
	m_pTable->DropTable();
	TRETURN
}
// }}


// {{ TCW_VAR_PROTOTYPE(13)
//*-----------------------------------------------------------------------
// @mfunc Commit with retaining
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCDropTable::Variation_13()
{
	TBEGIN
	BOOL				fExists;
	ITransactionLocal	*pITransactionLocal = NULL;
	VARIANT				vSupportedTxnDDL;

	TESTC_PROVIDER(VerifyInterface(m_pITableDefinition, IID_ITransactionLocal,
				SESSION_INTERFACE, (IUnknown**)&pITransactionLocal));

	VariantInit(&vSupportedTxnDDL);
	TESTC_PROVIDER(GetProperty(DBPROP_SUPPORTEDTXNDDL, DBPROPSET_DATASOURCEINFO, 
			g_pIDBInitialize, &vSupportedTxnDDL));
	
	TESTC(VT_I4 == vSupportedTxnDDL.vt);
	// what values should we accept?
	TESTC_PROVIDER(DBPROPVAL_TC_NONE != vSupportedTxnDDL.lVal);

	m_pTable->SetBuildColumnDesc(TRUE);
	TESTC_(m_hr = m_pTable->CreateTable(0,0), S_OK);

	TESTC_(m_hr = StartTransaction(pITransactionLocal), S_OK);

	switch(vSupportedTxnDDL.lVal)
	{
		case DBPROPVAL_TC_DML:
			//check for XACT_E_XTIONEXISTS
				CHECK(m_hr = m_pITableDefinition->DropTable(&m_pTable->GetTableID()), XACT_E_XTIONEXISTS);
			break;

		case DBPROPVAL_TC_DDL_IGNORE:
			// the statement is not transacted
		case DBPROPVAL_TC_ALL:
		case DBPROPVAL_TC_DDL_COMMIT:
			TESTC_(DropTableAndCheck(&m_pTable->GetTableID()), S_OK);
			break;

		case DBPROPVAL_TC_DDL_LOCK:
			// error should be returned
			TESTC_(DropTableAndCheck(&m_pTable->GetTableID()), S_OK);
			break;
			
		default:
			TESTC(FALSE);
	}

	if (DBPROPVAL_TC_DDL_COMMIT != vSupportedTxnDDL.lVal)
	{
		// commit retaining
		CHECK(m_hr = pITransactionLocal->Commit(TRUE, 0, 0), S_OK);
		// check retaining
		CHECK(pITransactionLocal->Abort(NULL, FALSE, FALSE), S_OK);
	}

	// check table existence
	CHECK(m_hr = m_pTable->DoesTableExist(&m_pTable->GetTableID(), &fExists), S_OK);
	COMPARE(fExists, DBPROPVAL_TC_DML == vSupportedTxnDDL.lVal);

CLEANUP:
	SAFE_RELEASE(pITransactionLocal);
	m_pTable->DropTable();
	TRETURN
}
// }}


// {{ TCW_VAR_PROTOTYPE(14)
//*-----------------------------------------------------------------------
// @mfunc Commit without retaining
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCDropTable::Variation_14()
{
	TBEGIN
	BOOL				fExists;
	ITransactionLocal	*pITransactionLocal = NULL;
	VARIANT				vSupportedTxnDDL;

	TESTC_PROVIDER(VerifyInterface(m_pITableDefinition, IID_ITransactionLocal,
				SESSION_INTERFACE, (IUnknown**)&pITransactionLocal));

	VariantInit(&vSupportedTxnDDL);
	TESTC_PROVIDER(GetProperty(DBPROP_SUPPORTEDTXNDDL, DBPROPSET_DATASOURCEINFO, 
			g_pIDBInitialize, &vSupportedTxnDDL));
	
	TESTC(VT_I4 == vSupportedTxnDDL.vt);
	// what values should we accept?
	TESTC_PROVIDER(DBPROPVAL_TC_NONE != vSupportedTxnDDL.lVal);

	m_pTable->SetBuildColumnDesc(TRUE);
	TESTC_(m_hr = m_pTable->CreateTable(0,0), S_OK);

	TESTC_(m_hr = StartTransaction(pITransactionLocal), S_OK);

	switch(vSupportedTxnDDL.lVal)
	{
		case DBPROPVAL_TC_DML:
			//check for XACT_E_XTIONEXISTS
				CHECK(m_hr = m_pITableDefinition->DropTable(&m_pTable->GetTableID()), XACT_E_XTIONEXISTS);
			break;

		case DBPROPVAL_TC_DDL_IGNORE:
			// the statement is not transacted
		case DBPROPVAL_TC_ALL:
		case DBPROPVAL_TC_DDL_COMMIT:
			TESTC_(DropTableAndCheck(&m_pTable->GetTableID()), S_OK);
			break;

		case DBPROPVAL_TC_DDL_LOCK:
			// error should be returned
			TESTC_(DropTableAndCheck(&m_pTable->GetTableID()), S_OK);
			break;
			
		default:
			TESTC(FALSE);
	}

	if (DBPROPVAL_TC_DDL_COMMIT != vSupportedTxnDDL.lVal)
	{
		// commit not retaining
		CHECK(m_hr = pITransactionLocal->Commit(FALSE, 0, 0), S_OK);
		// check not retaining
		CHECK(pITransactionLocal->Abort(NULL, FALSE, FALSE), 
			FAILED(m_hr)? S_OK: XACT_E_NOTRANSACTION);
	}

	// check whether the transaction was aborted
	CHECK(m_hr = m_pTable->DoesTableExist(&m_pTable->GetTableID(), &fExists), S_OK);
	COMPARE(fExists, DBPROPVAL_TC_DML == vSupportedTxnDDL.lVal);

CLEANUP:
	SAFE_RELEASE(pITransactionLocal);
	m_pTable->DropTable();
	TRETURN
}
// }}


// {{ TCW_VAR_PROTOTYPE(15)
//*-----------------------------------------------------------------------
// @mfunc Drop a table created with an SQL command => S_OK
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCDropTable::Variation_15()
{
	TBEGIN
	IDBCreateCommand	*pIDBCreateCommand = NULL;
	
	// check whether commands are supported
	TESTC_PROVIDER(VerifyInterface(m_pITableDefinition, IID_IDBCreateCommand,
		SESSION_INTERFACE, (IUnknown**)&pIDBCreateCommand));

	GetModInfo()->UseITableDefinition(FALSE);
	m_pTable->SetBuildColumnDesc(TRUE);
	TESTC_(m_hr = m_pTable->CreateTable(0, 0), S_OK);
	TESTC_(m_hr = m_pITableDefinition->DropTable(&m_pTable->GetTableID()), S_OK);

CLEANUP:
	SAFE_RELEASE(pIDBCreateCommand);
	GetModInfo()->UseITableDefinition(TRUE);
	m_pTable->DropTable();
	TRETURN
}
// }}


// {{ TCW_VAR_PROTOTYPE(16)
//*-----------------------------------------------------------------------
// @mfunc Drop a table created with ITableDefinition, no rowset created => S_OK
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCDropTable::Variation_16()
{
	BOOL	fTestRes = TEST_FAIL;

	m_pTable->SetBuildColumnDesc(TRUE);
	TESTC_(m_hr = m_pTable->CreateTable(10, 0), S_OK);
	TESTC_(m_hr = m_pITableDefinition->DropTable(&m_pTable->GetTableID()), S_OK);
	fTestRes = TEST_PASS;

CLEANUP:
	m_pTable->DropTable();
	return fTestRes;
}
// }}


// {{ TCW_VAR_PROTOTYPE(17)
//*-----------------------------------------------------------------------
// @mfunc Drop a table created with ITableDefinition, rowset released => S_OK
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCDropTable::Variation_17()
{
	BOOL	fTestRes = TEST_FAIL;
	IRowset	*pIRowset = NULL;

	m_pTable->SetRowset((IUnknown**)&pIRowset);
	m_pTable->SetRIID((struct _GUID*)&IID_IRowset);
	m_pTable->SetBuildColumnDesc(TRUE);
	TESTC_(m_hr = m_pTable->CreateTable(0, 0), S_OK);
	SAFE_RELEASE(pIRowset);
	TESTC_(m_hr = m_pITableDefinition->DropTable(&m_pTable->GetTableID()), S_OK);
	fTestRes = TEST_PASS;
CLEANUP:
	m_pTable->SetRowset(NULL);
	m_pTable->DropTable();
	return fTestRes;
}
// }}


// {{ TCW_VAR_PROTOTYPE(18)
//*-----------------------------------------------------------------------
// @mfunc ITableDefinition::CreateTable, insert 10 rows, release rowset, drop the table => S_OK
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCDropTable::Variation_18()
{
	BOOL	fTestRes = TEST_FAIL;
	IRowset	*pIRowset = NULL;

	m_pTable->SetRowset((IUnknown**)&pIRowset);
	m_pTable->SetRIID((struct _GUID*)&IID_IRowset);
	m_pTable->SetBuildColumnDesc(TRUE);
	TESTC_(m_hr = m_pTable->CreateTable(10, 0), S_OK);
	SAFE_RELEASE(pIRowset);
	TESTC_(m_hr = m_pITableDefinition->DropTable(&m_pTable->GetTableID()), S_OK);
	fTestRes = TEST_PASS;
CLEANUP:
	m_pTable->SetRowset(NULL);
	m_pTable->DropTable();
	return fTestRes;
}
// }}


// {{ TCW_VAR_PROTOTYPE(19)
//*-----------------------------------------------------------------------
// @mfunc For each provider type, create a table with a single column and then drop it => S_OK
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCDropTable::Variation_19()
{
	BOOL			fTestRes = TEST_PASS;
	DBORDINAL		i;
	DBCOLUMNDESC	*rgColumnDesc	= NULL;
	DBORDINAL		cColumnDesc		= 0;

	DuplicateColumnDesc(m_rgColumnDesc, m_cColumnDesc, &rgColumnDesc);
	cColumnDesc = m_cColumnDesc;
	ReleaseAllColumnPropSets(rgColumnDesc, cColumnDesc);
	m_pTable->SetBuildColumnDesc(FALSE);
	m_pTable->SetColumnDesc(rgColumnDesc, cColumnDesc);

	for (i=0; i<cColumnDesc; i++)
	{
		odtLog << "\t" << rgColumnDesc[i].pwszTypeName;
		m_pTable->SetColumnDesc(NULL);
		m_pTable->SetColumnDesc(&rgColumnDesc[i], 1);
		if (!CHECK(m_hr = m_pTable->CreateTable(0, 0), S_OK))
		{
			fTestRes = TEST_FAIL;
			continue;
		}

		if (!CHECK(m_hr = m_pITableDefinition->DropTable(&m_pTable->GetTableID()), S_OK))
		{
			odtLog << "\n Error for type" << rgColumnDesc[i].pwszTypeName << "\n";
			fTestRes = TEST_FAIL;
		}
		m_pTable->DropTable();
	}
	odtLog << "\n";
	
	m_pTable->SetColumnDesc(NULL);
	ReleaseColumnDesc(rgColumnDesc, cColumnDesc);
	return fTestRes;
}
// }}


// {{ TCW_VAR_PROTOTYPE(20)
//*-----------------------------------------------------------------------
// @mfunc Drop a table twice => DB_E_NOTABLE
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCDropTable::Variation_20()
{
	BOOL	fTestRes = TEST_FAIL;

	m_pTable->SetBuildColumnDesc(TRUE);
	TESTC_(m_hr = m_pTable->CreateTable(0, 0), S_OK);
	TESTC_(m_hr = m_pITableDefinition->DropTable(&m_pTable->GetTableID()), S_OK);
	TESTC_(m_hr = m_pITableDefinition->DropTable(&m_pTable->GetTableID()), DB_E_NOTABLE);
	fTestRes = TEST_PASS;

CLEANUP:	
	return fTestRes;
}
// }}


//----------------------------------------------------------------------
//
// @cmember Thread procedure for TCDropTable
//----------------------------------------------------------------------
unsigned TCDropTable::MyThreadProc(ULONG i)
{
	DBID			TableID;
	HRESULT			hr;

	if (i>= nThreads)
		return 0;
	TableID.eKind			= DBKIND_NAME;
	TableID.uName.pwszName	= m_rgName[i];
	Sleep(0); // switch the context

	hr = m_pITableDefinition->DropTable(&TableID);
	Sleep(0); // switch the context

	m_rgResult[i] = hr;
	return 1;
} //TCDropTable::MyThreadProc


// {{ TCW_VAR_PROTOTYPE(21)
//*-----------------------------------------------------------------------
// @mfunc threads on different tables
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCDropTable::Variation_21()
{ 
	unsigned		rgIDThread[nThreads];
	HANDLE			hrgThread[nThreads];
	CInParam		rgThreadParam[nThreads];
	BOOL			fTestResult = TEST_FAIL;
	ULONG			i;
	DBID			TableID;

	// create n names and init the results
	for (i=0; i<nThreads; i++)
	{
		m_rgName[i] = NULL;
		m_rgResult[i] = E_FAIL;
	}
	for (i=0; i< nThreads; i++)
	{
		m_pTable->SetBuildColumnDesc(TRUE);
		TESTC_(m_hr = m_pTable->CreateTable(0, 0), S_OK);
		m_rgName[i] = wcsDuplicate(m_pTable->GetTableName());		
		rgThreadParam[i].pObject	= this;
		rgThreadParam[i].i			= i;
	}
	
	// creates a table, build rgColumnDesc by it
	for (i=0; i<nThreads; i++)
	{
		hrgThread[i] = (HANDLE)_beginthreadex(NULL, 0, ThreadProc,
							(void*)&rgThreadParam[i],
							0, 
							&rgIDThread[i]);		// input param
		TESTC(0 != hrgThread[i]);
	}

	WaitForMultipleObjects(nThreads, (CONST HANDLE*)hrgThread, TRUE, 1000);
	Sleep(1000);
	for (i=0; i< nThreads; i++)
		CloseHandle(hrgThread[i]);

	for (i=0; i<nThreads; i++)
		TESTC_(m_rgResult[i], S_OK);
	fTestResult = TEST_PASS;

CLEANUP:
	TableID.eKind = DBKIND_NAME;
	for (i=0; i<nThreads; i++)
	{
		TableID.uName.pwszName = m_rgName[i];
		// if the table was not dropped by the corresponding thread, try again
		if (FAILED(m_rgResult[i]))
			CHECK(DropTableAndCheck(&TableID), S_OK);
		PROVIDER_FREE(m_rgName[i]);
	}
	return fTestResult;
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(22)
//*-----------------------------------------------------------------------
// @mfunc threads on same table
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCDropTable::Variation_22()
{ 
	unsigned		rgIDThread[nThreads];
	HANDLE			hrgThread[nThreads];
	CInParam		rgThreadParam[nThreads];
	BOOL			fTestResult		= TEST_FAIL;
	ULONG			i;
	ULONG			nS_OK			= 0;
	ULONG			nDB_E_NOTABLE	= 0;
	LPWSTR			pwszBaseName	= NULL;
	DBID			TableID;

	// create n names and init the results
	m_pTable->SetBuildColumnDesc(TRUE);
	TESTC_(m_hr = m_pTable->CreateTable(0, 0), S_OK);
	pwszBaseName = m_pTable->GetTableName();
	for (i=0; i< nThreads; i++)
	{
		m_rgResult[i]	= E_FAIL;
		m_rgName[i]		= pwszBaseName;
		rgThreadParam[i].pObject = this;
		rgThreadParam[i].i		= i;
	}
	
	// creates a table, build rgColumnDesc by it
	for (i=0; i<nThreads; i++)
	{
		hrgThread[i] = (HANDLE)_beginthreadex(NULL, 0, ThreadProc,
							(void*)&rgThreadParam[i],
							0, 
							&rgIDThread[i]);		// input param
		TESTC(0 != hrgThread[i]);
	}

	WaitForMultipleObjects(nThreads, (CONST HANDLE*)hrgThread, TRUE, 1000);
	Sleep(1000);
	for (i=0; i< nThreads; i++)
		CloseHandle(hrgThread[i]);

	for (i=nS_OK=nDB_E_NOTABLE=0; i<nThreads; i++)
	{
		if (m_rgResult[i] == S_OK)
			nS_OK++;
		else if (CHECK(m_rgResult[i], DB_E_NOTABLE))
			nDB_E_NOTABLE++;
		else
		{
			odtLog << "Thread " << i << ": unexpected result " << m_rgResult[i] << "\n";
			goto CLEANUP;
		}
	}

	TESTC(nS_OK == 1 && nDB_E_NOTABLE == nThreads-1);
	fTestResult = TEST_PASS;

CLEANUP:
	TableID.eKind = DBKIND_NAME;
	TableID.uName.pwszName = pwszBaseName;
	if (nS_OK < 1)
		CHECK(DropTableAndCheck(&TableID), S_OK);
	return fTestResult;
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(23)
//*-----------------------------------------------------------------------
// @mfunc Fully Qualified Table Name
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCDropTable::Variation_23()
{ 
	BOOL		fTestRes = TEST_FAIL;
	DBID		TableID;
	WCHAR		*pwszQualTableName = NULL;
	WCHAR		*pwszCatalogName = NULL;
	WCHAR		*pwszSchemaName = NULL;
	WCHAR		*pwszTableName = NULL;

	// create a regular table
	TESTC(NULL != m_pTable);
	m_pTable->SetBuildColumnDesc(TRUE);
	TESTC_(m_pTable->CreateTable(0, 0), S_OK);
	pwszTableName = m_pTable->GetTableName();
	TableID.eKind = DBKIND_NAME;

	TESTC(GetCatalogSchemaNames(pwszTableName, &pwszCatalogName, &pwszSchemaName));

	//Construct a fully Qualified TableName...
	TESTC_(m_pTable->GetQualifiedName(pwszCatalogName, pwszSchemaName, pwszTableName, &pwszQualTableName),S_OK);
	TableID.uName.pwszName = pwszQualTableName;

	// drop the table
	TESTC_(DropTableAndCheck(&TableID), S_OK);
	fTestRes = TEST_PASS;
    
CLEANUP:
	SAFE_FREE(pwszCatalogName);
	SAFE_FREE(pwszSchemaName);
	SAFE_FREE(pwszQualTableName);
	m_pTable->DropTable();
    return fTestRes;
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(24)
//*-----------------------------------------------------------------------
// @mfunc Quoted Table Name
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCDropTable::Variation_24()
{ 
	BOOL	fTestRes = TEST_FAIL;
	DBID	TableID;
	
	TableID.eKind = DBKIND_NAME;
	TableID.uName.pwszName = NULL;
	TESTC(NULL != m_pTable);
	m_pTable->SetBuildColumnDesc(TRUE);
	TESTC_(m_pTable->CreateTable(0, 0), S_OK);
	m_pTable->GetQuotedName(m_pTable->GetTableName(), &TableID.uName.pwszName);

	TESTC_(DropTableAndCheck(&TableID), S_OK);
	fTestRes = TEST_PASS;

CLEANUP:
	ReleaseDBID(&TableID, FALSE);
	m_pTable->DropTable();
	return fTestRes;
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(25)
//*-----------------------------------------------------------------------
// @mfunc Different DBKINDs for pTableID
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCDropTable::Variation_25()
{ 
	TBEGIN
	DBID			TableID;

	m_pTable->SetBuildColumnDesc(TRUE);

	// try to drop a column
	TableID.eKind			= DBKIND_NAME;
	TESTC_(m_hr = m_pTable->CreateTable(0, 0), S_OK);
	TableID.uName.pwszName	= m_pTable->GetTableID().uName.pwszName;

	TableID.eKind			= DBKIND_GUID;
	TableID.uGuid.guid		= guidModule;
	if (!CHECK(DropTableAndCheck(&TableID), DB_E_NOTABLE))
	{
		odtLog << "error at the guid case\n";
	}
	CHECK(m_hr = m_pTable->DropTable(), S_OK);
	
	TableID.eKind			= DBKIND_GUID_NAME;
	TableID.uGuid.guid		= guidModule;
	TESTC_(m_hr = m_pTable->CreateTable(0, 0), S_OK);
	TableID.uName.pwszName	= m_pTable->GetTableID().uName.pwszName;
	if (!CHECK(DropTableAndCheck(&TableID), DB_E_NOTABLE))
	{
		odtLog << "error at the guid name case\n";
	}
	CHECK(m_hr = m_pTable->DropTable(), S_OK);
	
	TableID.eKind			= DBKIND_GUID_PROPID;
	TableID.uGuid.guid		= guidModule;
	TableID.uName.ulPropid	= 0L;
	if (!CHECK(DropTableAndCheck(&TableID), DB_E_NOTABLE))
	{
		odtLog << "error at the guid propid case\n";
	}
	
	TableID.eKind			= DBKIND_PGUID_NAME;
	TableID.uGuid.pguid		= &guidModule;
	TESTC_(m_hr = m_pTable->CreateTable(0, 0), S_OK);
	TableID.uName.pwszName	= m_pTable->GetTableID().uName.pwszName;
	if (!CHECK(DropTableAndCheck(&TableID), DB_E_NOTABLE))
	{
		odtLog << "error at the pguid name case\n";
	}
	CHECK(m_hr = m_pTable->DropTable(), S_OK);
	
	TableID.eKind			= DBKIND_PGUID_PROPID;
	TableID.uGuid.pguid		= &guidModule;
	TableID.uName.ulPropid	= 0L;
	if (!CHECK(DropTableAndCheck(&TableID), DB_E_NOTABLE))
	{
		odtLog << "error at the pguid propid case\n";
	}
	
	TableID.eKind			= DBKIND_PROPID;
	TableID.uName.ulPropid	= 0L;
	if (!CHECK(DropTableAndCheck(&TableID), DB_E_NOTABLE))
	{
		odtLog << "error at the propid case\n";
	}
	
	TableID.eKind			= 0xff;
	if (!CHECK(DropTableAndCheck(&TableID), DB_E_NOTABLE))
	{
		odtLog << "error at the inexistent value for eKind case\n";
	}

CLEANUP:
	CHECK(m_hr = m_pTable->DropTable(), S_OK);
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END


// {{ TCW_TERMINATE_METHOD
//--------------------------------------------------------------------
// @mfunc TestCase Termination Routine
//
// @rdesc TRUE or FALSE
//
BOOL TCDropTable::Terminate()
{
	// TO DO:  Add your own code here

	// {{ TCW_TERM_BASECLASS_CHECK2
	return(TCITableDefinition::Terminate());
}	// }}
// }}
// }}


// {{ TCW_TC_PROTOTYPE(TCCreateTable)
//*-----------------------------------------------------------------------
//| Test Case:		TCCreateTable - TestCase for table creation
//|	Created:			09/11/97
//*-----------------------------------------------------------------------


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




// {{ TCW_VAR_PROTOTYPE(1)
//*-----------------------------------------------------------------------
// @mfunc Session interfaces
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCCreateTable::Variation_1()
{
	return DefaultObjectTesting(m_pITableDefinition, SESSION_INTERFACE);
}
// }}


// {{ TCW_VAR_PROTOTYPE(2)
//*-----------------------------------------------------------------------
// @mfunc pTableID is NULL => S_OK
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCCreateTable::Variation_2()
{
	TBEGIN
	DBCOLUMNDESC	*rgColumnDesc	= NULL;
	DBORDINAL		cColumnDesc		= 0;

	DuplicateColumnDesc(m_rgColumnDesc, m_cColumnDesc, &rgColumnDesc);
	cColumnDesc = m_cColumnDesc;
	ReleaseAllColumnPropSets(rgColumnDesc, cColumnDesc);

	TESTC_(CCNDropTable(NULL, cColumnDesc, rgColumnDesc, IID_IRowset, 0, NULL), S_OK);

CLEANUP:
	// checkings, etc
	ReleaseColumnDesc(rgColumnDesc, cColumnDesc);
	TRETURN
}
// }}


// {{ TCW_VAR_PROTOTYPE(3)
//*-----------------------------------------------------------------------
// @mfunc ppTableID is a NULL pointer => S_OK
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCCreateTable::Variation_3()
{
	TBEGIN
	DBID			TableID;
	DBCOLUMNDESC	*rgColumnDesc	= NULL;
	DBORDINAL		cColumnDesc		= 0;


	DuplicateColumnDesc(m_rgColumnDesc, m_cColumnDesc, &rgColumnDesc);
	cColumnDesc = m_cColumnDesc;
	ReleaseAllColumnPropSets(rgColumnDesc, cColumnDesc);

	m_pTable->MakeTableName(NULL);
	TableID.eKind			= DBKIND_NAME;
	TableID.uName.pwszName	= m_pTable->GetTableName();

	TESTC_(CCNDropTable(&TableID, cColumnDesc, rgColumnDesc, IID_IRowset,
			0, NULL), S_OK);	
	
CLEANUP:
	ReleaseColumnDesc(rgColumnDesc, cColumnDesc);
	TRETURN
}
// }}


// {{ TCW_VAR_PROTOTYPE(4)
//*-----------------------------------------------------------------------
// @mfunc pTableID and ppTableID both NULL => E_INVALIDARG
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCCreateTable::Variation_4()
{
	TBEGIN
	DBCOLUMNDESC	*rgColumnDesc	= NULL;
	DBORDINAL		cColumnDesc		= 0;

	DuplicateColumnDesc(m_rgColumnDesc, m_cColumnDesc, &rgColumnDesc);
	cColumnDesc = m_cColumnDesc;
	ReleaseAllColumnPropSets(rgColumnDesc, cColumnDesc);

	TESTC_(CCNDropTable(NULL, cColumnDesc, rgColumnDesc, IID_IRowset,
			0, NULL, TRUE), E_INVALIDARG);
		
CLEANUP:
	ReleaseColumnDesc(rgColumnDesc, cColumnDesc);
	TRETURN
}
// }}


// {{ TCW_VAR_PROTOTYPE(5)
//*-----------------------------------------------------------------------
// @mfunc *pTableID == DB_NULLID => DB_E_BADTABLEID
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCCreateTable::Variation_5()
{
	TBEGIN
	DBCOLUMNDESC	*rgColumnDesc	= NULL;
	DBORDINAL		cColumnDesc		= 0;

	DuplicateColumnDesc(m_rgColumnDesc, m_cColumnDesc, &rgColumnDesc);
	cColumnDesc = m_cColumnDesc;
	ReleaseAllColumnPropSets(rgColumnDesc, cColumnDesc);

	TESTC_(CCNDropTable((DBID*)&DB_NULLID, cColumnDesc, rgColumnDesc, IID_IRowset,
			0, NULL), DB_E_BADTABLEID);
	
CLEANUP:
	ReleaseColumnDesc(rgColumnDesc, cColumnDesc);
	TRETURN
}
// }}


// {{ TCW_VAR_PROTOTYPE(6)
//*-----------------------------------------------------------------------
// @mfunc cColumnDesc == 0 => E_INVALIDARG or S_OK
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCCreateTable::Variation_6()
{
	TBEGIN
	DBCOLUMNDESC	*rgColumnDesc	= NULL;
	DBORDINAL		cColumnDesc		= 0;

	DuplicateColumnDesc(m_rgColumnDesc, m_cColumnDesc, &rgColumnDesc);
	cColumnDesc = m_cColumnDesc;
	ReleaseAllColumnPropSets(rgColumnDesc, cColumnDesc);

	TEST2C_(CCNDropTable(NULL, 0, rgColumnDesc, IID_IRowset, 0, NULL), 
		S_OK, E_INVALIDARG);

CLEANUP:	
	ReleaseColumnDesc(rgColumnDesc, cColumnDesc);
	TRETURN
}
// }}


// {{ TCW_VAR_PROTOTYPE(7)
//*-----------------------------------------------------------------------
// @mfunc rgColumnDesc == NULL => E_INVALIDARG
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCCreateTable::Variation_7()
{
	TBEGIN

	TESTC_(CCNDropTable(NULL, m_cColumnDesc, NULL, IID_IRowset,
			0, NULL), E_INVALIDARG);

CLEANUP:
	TRETURN
}
// }}


// {{ TCW_VAR_PROTOTYPE(8)
//*-----------------------------------------------------------------------
// @mfunc cPropertySets != 0 and rgPropertySets == NULL => E_INVALIDARG
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCCreateTable::Variation_8()
{
	TBEGIN
	ULONG			ulNonZero = 2;
	DBCOLUMNDESC	*rgColumnDesc	= NULL;
	DBORDINAL		cColumnDesc		= 0;

	DuplicateColumnDesc(m_rgColumnDesc, m_cColumnDesc, &rgColumnDesc);
	cColumnDesc = m_cColumnDesc;
	ReleaseAllColumnPropSets(rgColumnDesc, cColumnDesc);

	TESTC_(CCNDropTable(NULL, cColumnDesc, rgColumnDesc, IID_IRowset,
			ulNonZero, NULL), E_INVALIDARG);
	
CLEANUP:
	ReleaseColumnDesc(rgColumnDesc, cColumnDesc);
	TRETURN
}
// }}


// {{ TCW_VAR_PROTOTYPE(9)
//*-----------------------------------------------------------------------
// @mfunc cPropertySets is 0 and rgPropertySets != NULL => S_OK
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCCreateTable::Variation_9()
{
	TBEGIN
	DBPROPSET		rgPropertySets[1];
	DBPROP			rgProp[1];
	DBCOLUMNDESC	*rgColumnDesc	= NULL;
	DBORDINAL		cColumnDesc		= 0;

	DuplicateColumnDesc(m_rgColumnDesc, m_cColumnDesc, &rgColumnDesc);
	cColumnDesc = m_cColumnDesc;
	ReleaseAllColumnPropSets(rgColumnDesc, cColumnDesc);

	FILL_PROP_SET(rgPropertySets[0], 1, rgProp, DBPROPSET_ROWSET)
	FILL_PROP(rgProp[0], DBPROP_IAccessor, VT_BOOL, V_BOOL, VARIANT_TRUE, DBPROPOPTIONS_REQUIRED)
		
	TESTC_(CCNDropTable(NULL, cColumnDesc, rgColumnDesc, IID_IRowset,
			0, rgPropertySets), S_OK);

CLEANUP:
	ReleaseColumnDesc(rgColumnDesc, cColumnDesc);
	TRETURN
}
// }}


// {{ TCW_VAR_PROTOTYPE(10)
//*-----------------------------------------------------------------------
// @mfunc for a property sets, cProperties != 0 and rgProperties == NULL => E_INVALIDARG
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCCreateTable::Variation_10()
{
	TBEGIN
	DBPROPSET		rgPropertySets[1];
	DBCOLUMNDESC	*rgColumnDesc	= NULL;
	DBORDINAL		cColumnDesc		= 0;

	DuplicateColumnDesc(m_rgColumnDesc, m_cColumnDesc, &rgColumnDesc);
	cColumnDesc = m_cColumnDesc;
	ReleaseAllColumnPropSets(rgColumnDesc, cColumnDesc);
	FILL_PROP_SET(rgPropertySets[0], 3, NULL, DBPROPSET_ROWSET)

	TESTC_(CCNDropTable(NULL, cColumnDesc, rgColumnDesc, IID_IRowset,
			1, rgPropertySets), E_INVALIDARG);

CLEANUP:	
	ReleaseColumnDesc(rgColumnDesc, cColumnDesc);
	TRETURN
}


// {{ TCW_VAR_PROTOTYPE(11)
//*-----------------------------------------------------------------------
// @mfunc cProperties == 0 on a property set => S_OK
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCCreateTable::Variation_11()
{
	TBEGIN
	DBPROPSET		rgPropertySets[1];
	DBPROP			rgProp[1];
	DBCOLUMNDESC	*rgColumnDesc	= NULL;
	DBORDINAL		cColumnDesc		= 0;

	DuplicateColumnDesc(m_rgColumnDesc, m_cColumnDesc, &rgColumnDesc);
	cColumnDesc = m_cColumnDesc;
	ReleaseAllColumnPropSets(rgColumnDesc, cColumnDesc);

//	FILL_PROP_SET(rgPropertySets[0], 0, rgProp, DBPROPSET_ROWSET)
	rgPropertySets[0].cProperties		= 0;						
	rgPropertySets[0].rgProperties		= rgProp;						
	rgPropertySets[0].guidPropertySet	= DBPROPSET_ROWSET;					

	TESTC_(CCNDropTable(NULL, cColumnDesc, rgColumnDesc, IID_IRowset, 1, rgPropertySets), S_OK);

CLEANUP:
	ReleaseColumnDesc(rgColumnDesc, cColumnDesc);
	TRETURN
}
// }}


// {{ TCW_VAR_PROTOTYPE(12)
//*-----------------------------------------------------------------------
// @mfunc for a column, rgPropertySets is NULL though cPropertySets != 0 => E_INVALIDARG
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCCreateTable::Variation_12()
{
	TBEGIN
	ULONG			cProp = 3;
	DBPROPSET		rgPropSets[1];
	DBCOLUMNDESC	*rgColumnDesc	= NULL;
	DBORDINAL		cColumnDesc		= 0;

	DuplicateColumnDesc(m_rgColumnDesc, m_cColumnDesc, &rgColumnDesc);
	cColumnDesc = m_cColumnDesc;
	ReleaseAllColumnPropSets(rgColumnDesc, cColumnDesc);

	rgColumnDesc[0].rgPropertySets	= rgPropSets;
	rgColumnDesc[0].cPropertySets	= NUMELEM(rgPropSets);
	FILL_PROP_SET(rgPropSets[0], cProp, NULL, DBPROPSET_COLUMN)

	TESTC_(CCNDropTable(NULL, cColumnDesc, rgColumnDesc, IID_IRowset, 0, NULL), E_INVALIDARG);
	
CLEANUP:
	// it is not required to release the memory for rgColumnDesc; it will be release in table destructor
	rgColumnDesc[0].rgPropertySets	= NULL;
	rgColumnDesc[0].cPropertySets	= 0;
	ReleaseColumnDesc(rgColumnDesc, cColumnDesc);
	TRETURN
}
// }}


// {{ TCW_VAR_PROTOTYPE(13)
//*-----------------------------------------------------------------------
// @mfunc dbcid in an element of rgColumnDesc is DB_NULLID => DB_E_BADCOLUMNID
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCCreateTable::Variation_13()
{
	TBEGIN
	DBCOLUMNDESC	*rgColumnDesc	= NULL;
	DBORDINAL		cColumnDesc		= 0;

	DuplicateColumnDesc(m_rgColumnDesc, m_cColumnDesc, &rgColumnDesc);
	cColumnDesc = m_cColumnDesc;
	ReleaseAllColumnPropSets(rgColumnDesc, cColumnDesc);
	// set a dbcid of an element in rgColumnDesc to DB_NULLID
	ReleaseDBID(&rgColumnDesc[0].dbcid, FALSE);		// cleans the container
	memcpy(&rgColumnDesc[0].dbcid, &DB_NULLID, sizeof(DBID));

	TESTC_(CCNDropTable(NULL, cColumnDesc, rgColumnDesc, IID_IRowset, 0, NULL), DB_E_BADCOLUMNID);

CLEANUP:
	ReleaseColumnDesc(rgColumnDesc, cColumnDesc);
	TRETURN
}
// }}


// {{ TCW_VAR_PROTOTYPE(14)
//*-----------------------------------------------------------------------
// @mfunc dbcid in an element of rgColumnDesc is NULL => DB_E_BADCOLUMNID
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCCreateTable::Variation_14()
{
	TBEGIN
	DBCOLUMNDESC	*rgColumnDesc	= NULL;
	DBORDINAL		cColumnDesc		= 0;

	DuplicateColumnDesc(m_rgColumnDesc, m_cColumnDesc, &rgColumnDesc);
	cColumnDesc = m_cColumnDesc;
	ReleaseAllColumnPropSets(rgColumnDesc, cColumnDesc);

	// set a dbcid of an element in rgColumnDesc to DB_NULLID
	ReleaseDBID(&rgColumnDesc[0].dbcid, FALSE);		// cleans the container
	rgColumnDesc[0].dbcid.eKind				= DBKIND_NAME;
	rgColumnDesc[0].dbcid.uName.pwszName	= NULL;

	TESTC_(CCNDropTable(NULL, cColumnDesc, rgColumnDesc, IID_IRowset, 0, NULL), DB_E_BADCOLUMNID);

CLEANUP:
	ReleaseColumnDesc(rgColumnDesc, cColumnDesc);
	TRETURN
}
// }}


// {{ TCW_VAR_PROTOTYPE(15)
//*-----------------------------------------------------------------------
// @mfunc not null pclsid in a DBCOLUMNDESC element
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCCreateTable::Variation_15()
{
	TBEGIN
	DBCOLUMNDESC	*rgColumnDesc	= NULL;
	DBORDINAL		cColumnDesc		= 0;
	POSITION		pos;
	CCol			col;
	HRESULT			hr;
	BOOL			fOleSupported	= FALSE;

	DuplicateColumnDesc(m_rgColumnDesc, m_cColumnDesc, &rgColumnDesc);
	cColumnDesc = m_cColumnDesc;
	ReleaseAllColumnPropSets(rgColumnDesc, cColumnDesc);

	// set pclsid to IID_NULL
	rgColumnDesc[0].pclsid = (GUID*)&IID_NULL;

	// check whether this is ignored for a non-DBTYPE_IUNKNOWN column
	TESTC_(CCNDropTable(NULL, cColumnDesc, rgColumnDesc, IID_IRowset, 0, NULL), S_OK);

	// check DBTYPE_IUNKNOWN is supported
	for (pos = m_ColList.GetHeadPosition(); pos; )
	{
		col = m_ColList.GetNext(pos);
		if (DBTYPE_IUNKNOWN == col.GetProviderType())
		{
			fOleSupported = TRUE;
			break;
		}
	}

	// check whether a DBTYPE_IUNKNOWN column can be created in the table
	rgColumnDesc[0].wType	= DBTYPE_IUNKNOWN;
	PROVIDER_FREE(rgColumnDesc[0].pwszTypeName);
	if (fOleSupported)
		rgColumnDesc[0].pwszTypeName = wcsDuplicate(col.GetProviderTypeName());
	hr = fOleSupported ? S_OK : DB_E_BADTYPE;
	TESTC_(CCNDropTable(NULL, cColumnDesc, rgColumnDesc, IID_IRowset, 0, NULL), hr);

CLEANUP:
	rgColumnDesc[0].pclsid = NULL;
	ReleaseColumnDesc(rgColumnDesc, cColumnDesc);
	TRETURN
}
// }}


// {{ TCW_VAR_PROTOTYPE(16)
//*-----------------------------------------------------------------------
// @mfunc empty column name => DB_E_BADCOLUMNID
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCCreateTable::Variation_16()
{
	TBEGIN
	DBCOLUMNDESC	*rgColumnDesc	= NULL;
	DBORDINAL		cColumnDesc		= 0;

	DuplicateColumnDesc(m_rgColumnDesc, m_cColumnDesc, &rgColumnDesc);
	cColumnDesc = m_cColumnDesc;
	ReleaseAllColumnPropSets(rgColumnDesc, cColumnDesc);
	// set a dbcid of an element in rgColumnDesc to DB_NULLID
	rgColumnDesc[0].dbcid.eKind				= DBKIND_NAME;
	ReleaseDBID(&rgColumnDesc[0].dbcid, FALSE);		// cleans the container
	rgColumnDesc[0].dbcid.uName.pwszName	= wcsDuplicate(L"");

	TESTC_(CCNDropTable(NULL, cColumnDesc, rgColumnDesc, IID_IRowset, 0, NULL), DB_E_BADCOLUMNID);

CLEANUP:
	ReleaseColumnDesc(rgColumnDesc, cColumnDesc);
	TRETURN
}
// }}


// {{ TCW_VAR_PROTOTYPE(17)
//*-----------------------------------------------------------------------
// @mfunc empty table name => DB_E_BADTABLEID
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCCreateTable::Variation_17()
{
	TBEGIN
	DBID			TableID;
	DBCOLUMNDESC	*rgColumnDesc	= NULL;
	DBORDINAL		cColumnDesc		= 0;

	DuplicateColumnDesc(m_rgColumnDesc, m_cColumnDesc, &rgColumnDesc);
	cColumnDesc = m_cColumnDesc;
	ReleaseAllColumnPropSets(rgColumnDesc, cColumnDesc);

	TableID.eKind			= DBKIND_NAME;
	TableID.uName.pwszName	= L"";

	// create the empty name table
	TESTC_(CCNDropTable(&TableID, cColumnDesc, rgColumnDesc, IID_IRowset, 0, NULL), DB_E_BADTABLEID);

CLEANUP:
	ReleaseColumnDesc(rgColumnDesc, cColumnDesc);
	TRETURN
}
// }}


// {{ TCW_VAR_PROTOTYPE(18)
//*-----------------------------------------------------------------------
// @mfunc Maximum length for table name => S_OK
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCCreateTable::Variation_18()
{
	TBEGIN
	DBID			TableID;
	DBCOLUMNDESC	*rgColumnDesc	= NULL;
	DBORDINAL		cColumnDesc		= 0;

	DuplicateColumnDesc(m_rgColumnDesc, m_cColumnDesc, &rgColumnDesc);
	cColumnDesc = m_cColumnDesc;
	ReleaseAllColumnPropSets(rgColumnDesc, cColumnDesc);

	// create a maximum size table name 
	m_pTable->MakeTableName(NULL);
	TableID.eKind			= DBKIND_NAME;
	TableID.uName.pwszName	= BuildValidName(m_cMaxTableName, m_pTable->GetTableName());

	TESTC_(CCNDropTable(&TableID, cColumnDesc, rgColumnDesc, IID_IRowset, 0, NULL), S_OK);

CLEANUP:
	ReleaseDBID(&TableID, FALSE);
	ReleaseColumnDesc(rgColumnDesc, cColumnDesc);
	TRETURN
}
// }}


// {{ TCW_VAR_PROTOTYPE(19)
//*-----------------------------------------------------------------------
// @mfunc 1 char too long table name => DB_E_BADTABLEID
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCCreateTable::Variation_19()
{
	TBEGIN
	DBID			TableID;
	DBCOLUMNDESC	*rgColumnDesc	= NULL;
	DBORDINAL		cColumnDesc		= 0;

	DuplicateColumnDesc(m_rgColumnDesc, m_cColumnDesc, &rgColumnDesc);
	cColumnDesc = m_cColumnDesc;
	ReleaseAllColumnPropSets(rgColumnDesc, cColumnDesc);

	// create a maximum size table name 
	m_pTable->MakeTableName(NULL);
	TableID.eKind			= DBKIND_NAME;
	TableID.uName.pwszName = BuildValidName(m_cMaxTableName+1, m_pTable->GetTableName());

	TESTC_(CCNDropTable(&TableID, cColumnDesc, rgColumnDesc, IID_IRowset, 0, NULL), DB_E_BADTABLEID);

CLEANUP:
	ReleaseDBID(&TableID, FALSE);
	ReleaseColumnDesc(rgColumnDesc, cColumnDesc);
	TRETURN
}
// }}


// {{ TCW_VAR_PROTOTYPE(20)
//*-----------------------------------------------------------------------
// @mfunc Maximum length column name => S_OK
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCCreateTable::Variation_20()
{
	TBEGIN
	LPWSTR			pwszColumnName = NULL;
	DBCOLUMNDESC	*rgColumnDesc	= NULL;
	DBORDINAL		cColumnDesc		= 0;

	DuplicateColumnDesc(m_rgColumnDesc, m_cColumnDesc, &rgColumnDesc);
	cColumnDesc = m_cColumnDesc;
	ReleaseAllColumnPropSets(rgColumnDesc, cColumnDesc);

	// set a dbcid of an element in rgColumnDesc to DB_NULLID
	pwszColumnName = rgColumnDesc[0].dbcid.uName.pwszName;
	rgColumnDesc[0].dbcid.eKind = DBKIND_NAME;
	rgColumnDesc[0].dbcid.uName.pwszName	= BuildValidName(m_cMaxColName, pwszColumnName);
	// save the number of propertySets, to be able to release it ok

	TESTC_(CCNDropTable(NULL, cColumnDesc, rgColumnDesc, IID_IRowset, 0, NULL), S_OK);

CLEANUP:
	PROVIDER_FREE(pwszColumnName);
	ReleaseColumnDesc(rgColumnDesc, cColumnDesc);
	TRETURN
}
// }}


// {{ TCW_VAR_PROTOTYPE(21)
//*-----------------------------------------------------------------------
// @mfunc 1 char too long column name => DB_E_BADCOLUMNID
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCCreateTable::Variation_21()
{
	TBEGIN
	WCHAR			*pwszColumnName	= NULL;
	DBCOLUMNDESC	*rgColumnDesc	= NULL;
	DBORDINAL		cColumnDesc		= 0;

	DuplicateColumnDesc(m_rgColumnDesc, m_cColumnDesc, &rgColumnDesc);
	cColumnDesc = m_cColumnDesc;
	ReleaseAllColumnPropSets(rgColumnDesc, cColumnDesc);

	if (DBKIND_NAME == rgColumnDesc[0].dbcid.eKind)
		pwszColumnName = rgColumnDesc[0].dbcid.uName.pwszName;
	else
		pwszColumnName = wcsDuplicate(L"ColumnName");
	rgColumnDesc[0].dbcid.eKind			= DBKIND_NAME;
	rgColumnDesc[0].dbcid.uName.pwszName	= BuildValidName(m_cMaxColName+1, pwszColumnName);
	// save the number of propertySets, to be able to release it ok

	TESTC_(CCNDropTable(NULL, cColumnDesc, rgColumnDesc, IID_IRowset, 0, NULL), DB_E_BADCOLUMNID);

CLEANUP:
	PROVIDER_FREE(pwszColumnName);
	ReleaseColumnDesc(rgColumnDesc, cColumnDesc);
	TRETURN
}
// }}


// {{ TCW_VAR_PROTOTYPE(22)
//*-----------------------------------------------------------------------
// @mfunc ulColumnSize 0 for a variable-length column => S_OK
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCCreateTable::Variation_22()
{
	TBEGIN
	DBCOLUMNDESC	*rgColumnDesc	= NULL;
	DBORDINAL		cColumnDesc		= 0;

	DuplicateColumnDesc(m_rgColumnDesc, m_cColumnDesc, &rgColumnDesc);
	cColumnDesc = m_cColumnDesc;
	ReleaseAllColumnPropSets(rgColumnDesc, cColumnDesc);

	// go through the list of column and set the column size to 0 for all variable-length columns
	for (ULONG i=0; i<cColumnDesc; i++)
	{
		if (!IsFixedLength(rgColumnDesc[i].wType))
		{
			rgColumnDesc[i].ulColumnSize = 0;
			odtLog << "Column " << rgColumnDesc[i].dbcid.uName.pwszName << " is set to length 0!\n";
		}

		CHECK(CCNDropTable(NULL, cColumnDesc, rgColumnDesc, IID_IRowset, 0, NULL), S_OK);
	}

	ReleaseColumnDesc(rgColumnDesc, cColumnDesc);
	TRETURN
}
// }}


// {{ TCW_VAR_PROTOTYPE(23)
//*-----------------------------------------------------------------------
// @mfunc For each provider type create and drop a table with a single column => S_OK
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCCreateTable::Variation_23()
{
	TBEGIN
	DBCOLUMNDESC	*tempColumnDesc;
	DBORDINAL		i;
	DBCOLUMNDESC	*rgColumnDesc	= NULL;
	DBORDINAL		cColumnDesc		= 0;

	DuplicateColumnDesc(m_rgColumnDesc, m_cColumnDesc, &rgColumnDesc);
	cColumnDesc = m_cColumnDesc;
	ReleaseAllColumnPropSets(rgColumnDesc, cColumnDesc);

	// go through the list of column and set the column size to 0 for all variable-length columns
	for (i=0, tempColumnDesc=rgColumnDesc; i<cColumnDesc; i++, tempColumnDesc++)
	{
		odtLog << "Create a table with a single column " << tempColumnDesc->dbcid.uName.pwszName << "\n";
		CHECK(CCNDropTable(NULL, 1, tempColumnDesc, IID_IRowset, 0, NULL), S_OK);
	}

	ReleaseColumnDesc(rgColumnDesc, cColumnDesc);
	TRETURN
}
// }}


// {{ TCW_VAR_PROTOTYPE(24)
//*-----------------------------------------------------------------------
// @mfunc invalid table name => DB_E_BADTABLEID
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCCreateTable::Variation_24()
{
	TBEGIN
	WCHAR			*pwszTableName = NULL; 
	size_t			n, m;
	DBID			TableID;
	DBCOLUMNDESC	*rgColumnDesc	= NULL;
	DBORDINAL		cColumnDesc		= 0;

	DuplicateColumnDesc(m_rgColumnDesc, m_cColumnDesc, &rgColumnDesc);
	cColumnDesc = m_cColumnDesc;
	ReleaseAllColumnPropSets(rgColumnDesc, cColumnDesc);

	m_pTable->MakeTableName(NULL);
	TableID.eKind			= DBKIND_NAME;
	m = min(n=wcslen(m_pTable->GetTableName())+5, m_cMaxTableName);
	pwszTableName = BuildInvalidName(m, m_pTable->GetTableName(), m_pwszInvalidTableChars);
	TableID.uName.pwszName	= pwszTableName;

	TESTC_(CCNDropTable(&TableID, cColumnDesc, rgColumnDesc, IID_IRowset, 0, NULL), DB_E_BADTABLEID);

CLEANUP:
	PROVIDER_FREE(pwszTableName);
	ReleaseColumnDesc(rgColumnDesc, cColumnDesc);
	TRETURN
}
// }}


// {{ TCW_VAR_PROTOTYPE(25)
//*-----------------------------------------------------------------------
// @mfunc pTableID provides the name of an existing table => DB_E_DUPLICATETABLEID
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCCreateTable::Variation_25()
{
	TBEGIN
	DBID			TableID;
	DBCOLUMNDESC	*rgColumnDesc	= NULL;
	DBORDINAL		cColumnDesc		= 0;

	DuplicateColumnDesc(m_rgColumnDesc, m_cColumnDesc, &rgColumnDesc);
	cColumnDesc = m_cColumnDesc;
	ReleaseAllColumnPropSets(rgColumnDesc, cColumnDesc);

	m_pTable->MakeTableName(NULL);
	TableID.eKind			= DBKIND_NAME;
	TableID.uName.pwszName	= m_pTable->GetTableName();

	TESTC_(CreateAndCheckTable(m_pITableDefinition, NULL, &TableID, 
		cColumnDesc, rgColumnDesc, IID_IRowset, 0, NULL, NULL, NULL), S_OK);
	TESTC_(CCNDropTable(&TableID, cColumnDesc, rgColumnDesc, IID_IRowset, 0, NULL), DB_E_DUPLICATETABLEID);
	
CLEANUP:
	CHECK(DropTableAndCheck(&TableID), S_OK);
	ReleaseColumnDesc(rgColumnDesc, cColumnDesc);
	TRETURN
}
// }}


// {{ TCW_VAR_PROTOTYPE(26)
//*-----------------------------------------------------------------------
// @mfunc valid riid and NULL ppRowset => S_OK
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCCreateTable::Variation_26()
{
	TBEGIN
	DBID			*pTableID		= NULL;
	DBCOLUMNDESC	*rgColumnDesc	= NULL;
	DBORDINAL		cColumnDesc		= 0;

	DuplicateColumnDesc(m_rgColumnDesc, m_cColumnDesc, &rgColumnDesc);
	cColumnDesc = m_cColumnDesc;
	ReleaseAllColumnPropSets(rgColumnDesc, cColumnDesc);

	TESTC_(CreateAndCheckTable(m_pITableDefinition, NULL, NULL, 
		cColumnDesc, rgColumnDesc, IID_IRowset, 0, NULL, &pTableID, NULL), S_OK);
	
CLEANUP:
	CHECK(DropTableAndCheck(pTableID), S_OK);
	ReleaseDBID(pTableID);
	ReleaseColumnDesc(rgColumnDesc, cColumnDesc);
	TRETURN
}
// }}


// {{ TCW_VAR_PROTOTYPE(27)
//*-----------------------------------------------------------------------
// @mfunc invalid column name => DB_E_BADCOLUMNID
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCCreateTable::Variation_27()
{
	TBEGIN
	WCHAR			*pwszColName = NULL; 
	size_t			n, m;
	DBCOLUMNDESC	*rgColumnDesc	= NULL;
	DBORDINAL		cColumnDesc		= 0;

	DuplicateColumnDesc(m_rgColumnDesc, m_cColumnDesc, &rgColumnDesc);
	cColumnDesc = m_cColumnDesc;
	ReleaseAllColumnPropSets(rgColumnDesc, cColumnDesc);

	// create an invalid column name 
	m = min(n=wcslen(rgColumnDesc[0].dbcid.uName.pwszName)+5, m_cMaxColName);
	if (DBKIND_NAME == rgColumnDesc[0].dbcid.eKind)
		pwszColName = rgColumnDesc[0].dbcid.uName.pwszName;
	else
		pwszColName = wcsDuplicate(L"ColumnName");
	rgColumnDesc[0].dbcid.eKind = DBKIND_NAME;
	rgColumnDesc[0].dbcid.uName.pwszName = BuildInvalidName(m, 
		pwszColName, m_pwszInvalidColChars);
	SAFE_FREE(pwszColName);

	TESTC_(CCNDropTable(NULL, cColumnDesc, rgColumnDesc, IID_IRowset, 0, NULL), DB_E_BADCOLUMNID);

CLEANUP:
	ReleaseColumnDesc(rgColumnDesc, cColumnDesc);
	TRETURN
}
// }}


// {{ TCW_VAR_PROTOTYPE(28)
//*-----------------------------------------------------------------------
// @mfunc invalid type name for a column (NULL, empty or inexistent
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCCreateTable::Variation_28()
{
	TBEGIN
	DBCOLUMNDESC	*rgColumnDesc	= NULL;
	DBORDINAL		cColumnDesc		= 0;

	DuplicateColumnDesc(m_rgColumnDesc, m_cColumnDesc, &rgColumnDesc);
	cColumnDesc = m_cColumnDesc;
	ReleaseAllColumnPropSets(rgColumnDesc, cColumnDesc);

	// build the column type name
	SAFE_FREE(rgColumnDesc[0].pwszTypeName);

	odtLog << "NULL type name\n";
	rgColumnDesc[0].pwszTypeName = NULL;
	CHECK(CCNDropTable(NULL, cColumnDesc, rgColumnDesc, IID_IRowset, 0, NULL), S_OK); 

	// verify empty string (bug 26380, empty string for type name should be equivalent to specifying a NULL pointer)
	odtLog << "empty type name for a column\n";
	rgColumnDesc[0].pwszTypeName = wcsDuplicate(L"");
	CHECK(CCNDropTable(NULL, cColumnDesc, rgColumnDesc, IID_IRowset, 0, NULL), S_OK);

	rgColumnDesc[0].pwszTypeName = wcsDuplicate(L"Pay a trip to Europe");
	odtLog << "invalid type name (" << rgColumnDesc[0].pwszTypeName <<")\n";
	TESTC_(CCNDropTable(NULL, cColumnDesc, rgColumnDesc, IID_IRowset, 0, NULL), DB_E_BADTYPE);
	

CLEANUP:
	ReleaseColumnDesc(rgColumnDesc, cColumnDesc);
	TRETURN
}
// }}


// {{ TCW_VAR_PROTOTYPE(29)
//*-----------------------------------------------------------------------
// @mfunc invalid wType for a column => DB_E_BADTYPE
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCCreateTable::Variation_29()
{
	TBEGIN
	DBTYPE			wInvalidType	= 0xffff;
	DBCOLUMNDESC	*rgColumnDesc	= NULL;
	DBORDINAL		cColumnDesc		= 0;

	DuplicateColumnDesc(m_rgColumnDesc, m_cColumnDesc, &rgColumnDesc);
	cColumnDesc = m_cColumnDesc;
	ReleaseAllColumnPropSets(rgColumnDesc, cColumnDesc);

	PROVIDER_FREE(rgColumnDesc[0].pwszTypeName);
	rgColumnDesc[0].pwszTypeName = NULL;
	rgColumnDesc[0].wType = wInvalidType;

	TESTC_(CCNDropTable(NULL, cColumnDesc, rgColumnDesc, IID_IRowset, 0, NULL), DB_E_BADTYPE);

CLEANUP:
	ReleaseColumnDesc(rgColumnDesc, cColumnDesc);
	TRETURN
}
// }}


// {{ TCW_VAR_PROTOTYPE(30)
//*-----------------------------------------------------------------------
// @mfunc wType and pswzTypeName mismatch in a column description => DB_E_BADTYPE
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCCreateTable::Variation_30()
{
	TBEGIN
	DBCOLUMNDESC	*rgColumnDesc	= NULL;
	DBORDINAL		cColumnDesc		= 0;

	DuplicateColumnDesc(m_rgColumnDesc, m_cColumnDesc, &rgColumnDesc);
	cColumnDesc = m_cColumnDesc;
	ReleaseAllColumnPropSets(rgColumnDesc, cColumnDesc);

	// set an invalid wType
	TESTC_PROVIDER(cColumnDesc >= 7);
	
	// each column was assigned a different type; try to mismatch a pwszTypeName and wType for the first col
	PROVIDER_FREE(rgColumnDesc[0].pwszTypeName);
	rgColumnDesc[0].pwszTypeName	= rgColumnDesc[7].pwszTypeName;

	TESTC_(CCNDropTable(NULL, cColumnDesc, rgColumnDesc, IID_IRowset, 0, NULL), DB_E_BADTYPE);

CLEANUP:
	if (cColumnDesc > 1)
		rgColumnDesc[0].pwszTypeName = NULL;
	ReleaseColumnDesc(rgColumnDesc, cColumnDesc);
	TRETURN
}
// }}


// {{ TCW_VAR_PROTOTYPE(31)
//*-----------------------------------------------------------------------
// @mfunc not null pTypeInfo => DB_E_BADTYPE (for the time being
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCCreateTable::Variation_31()
{
	TBEGIN
	DBCOLUMNDESC	*rgColumnDesc	= NULL;
	DBORDINAL		cColumnDesc		= 0;

	DuplicateColumnDesc(m_rgColumnDesc, m_cColumnDesc, &rgColumnDesc);
	cColumnDesc = m_cColumnDesc;
	ReleaseAllColumnPropSets(rgColumnDesc, cColumnDesc);

	// set a not NULL pTypeInfo
	rgColumnDesc[0].pTypeInfo = (ITypeInfo*)pITableDefinition();

	TEST2C_(CCNDropTable(NULL, cColumnDesc, rgColumnDesc, IID_IRowset, 0, NULL), E_NOINTERFACE, DB_E_BADTYPE);

CLEANUP:
	ReleaseColumnDesc(rgColumnDesc, cColumnDesc);
	TRETURN
}
// }}


// {{ TCW_VAR_PROTOTYPE(32)
//*-----------------------------------------------------------------------
// @mfunc duplicate column identifiers => DB_E_DUPLICATECOLUMNID
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCCreateTable::Variation_32()
{
	TBEGIN
	DBCOLUMNDESC	*rgColumnDesc	= NULL;
	DBORDINAL		cColumnDesc		= 0;

	DuplicateColumnDesc(m_rgColumnDesc, m_cColumnDesc, &rgColumnDesc);
	cColumnDesc = m_cColumnDesc;
	ReleaseAllColumnPropSets(rgColumnDesc, cColumnDesc);

	// set an invalid wType
	TESTC_PROVIDER(2 < cColumnDesc);

	// each column was assigned a different type; try to mismatch a pwszTypeName and wType for the first col
	ReleaseDBID(&rgColumnDesc[0].dbcid, FALSE);
	DuplicateDBID(rgColumnDesc[1].dbcid, &rgColumnDesc[0].dbcid);

	TESTC_(CCNDropTable(NULL, cColumnDesc, rgColumnDesc, IID_IRowset, 0, NULL), DB_E_DUPLICATECOLUMNID);

CLEANUP:
	memset(&rgColumnDesc[0].dbcid, 0, sizeof(DBID));
	ReleaseColumnDesc(rgColumnDesc, cColumnDesc);
	TRETURN
}
// }}


// {{ TCW_VAR_PROTOTYPE(33)
//*-----------------------------------------------------------------------
// @mfunc improper eKind value in a DBID => DB_E_BADCOLUMNID
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCCreateTable::Variation_33()
{
	TBEGIN
	DBCOLUMNDESC	*rgColumnDesc	= NULL;
	DBORDINAL		cColumnDesc		= 0;

	DuplicateColumnDesc(m_rgColumnDesc, m_cColumnDesc, &rgColumnDesc);
	cColumnDesc = m_cColumnDesc;
	ReleaseAllColumnPropSets(rgColumnDesc, cColumnDesc);

	// set improper eKind in a column DBID
	ReleaseDBID(&rgColumnDesc[0].dbcid, FALSE);
	rgColumnDesc[0].dbcid.eKind	= INVALID_DBKIND;

	TESTC_(CCNDropTable(NULL, cColumnDesc, rgColumnDesc, IID_IRowset, 0, NULL), DB_E_BADCOLUMNID);

CLEANUP:
	ReleaseColumnDesc(rgColumnDesc, cColumnDesc);
	TRETURN
}
// }}


// {{ TCW_VAR_PROTOTYPE(34)
//*-----------------------------------------------------------------------
// @mfunc invalid property value on column
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCCreateTable::Variation_34()
{
	TBEGIN
	DBPROPSET		rgPropSet[1];
	DBPROP			rgProp[1];
	LONG			lValue = 12;
	DBCOLUMNDESC	*rgColumnDesc	= NULL;
	DBORDINAL		cColumnDesc		= 0;

	DuplicateColumnDesc(m_rgColumnDesc, m_cColumnDesc, &rgColumnDesc);
	cColumnDesc = m_cColumnDesc;
	ReleaseAllColumnPropSets(rgColumnDesc, cColumnDesc);

	// set improper value (different type than required) for a property value of a column 
	// DBPROPOPTIONS_REQUIRED
	rgColumnDesc[0].cPropertySets	= NUMELEM(rgPropSet);
	rgColumnDesc[0].rgPropertySets	= rgPropSet;
	FILL_PROP_SET(rgPropSet[0], NUMELEM(rgProp), rgProp, DBPROPSET_COLUMN)
	FILL_PROP(rgProp[0], DBPROP_COL_UNIQUE, DBTYPE_I4, V_I4, lValue, DBPROPOPTIONS_REQUIRED)
	CHECK(CCNDropTable(NULL, cColumnDesc, rgColumnDesc, IID_IRowset, 0, NULL), DB_E_ERRORSOCCURRED);

	// set improper value (different type) for a column DBPROPOPTIONS_OPTIONAL
	// try to set the property value of the rowset trough a column
	rgColumnDesc[0].cPropertySets	= NUMELEM(rgPropSet);
	rgColumnDesc[0].rgPropertySets	= rgPropSet;
	FILL_PROP_SET(rgPropSet[0], NUMELEM(rgProp), rgProp, DBPROPSET_COLUMN)
	FILL_PROP(rgProp[0], DBPROP_COL_UNIQUE, DBTYPE_I4, V_I4, lValue, DBPROPOPTIONS_OPTIONAL)
	CHECK(CCNDropTable(NULL, cColumnDesc, rgColumnDesc, IID_IRowset, 0, NULL), DB_S_ERRORSOCCURRED);

	// try to set a rowset property through a column, DBPROPOPTIONS_REQUIRED
	rgColumnDesc[0].cPropertySets		= NUMELEM(rgPropSet);
	rgColumnDesc[0].rgPropertySets	= rgPropSet;
	FILL_PROP_SET(rgPropSet[0], NUMELEM(rgProp), rgProp, DBPROPSET_ROWSET)
	FILL_PROP(rgProp[0], DBPROP_BOOKMARKS, DBTYPE_I4, V_I4, lValue, DBPROPOPTIONS_REQUIRED)
	CHECK(CCNDropTable(NULL, cColumnDesc, rgColumnDesc, IID_IRowset, 0, NULL), DB_E_ERRORSOCCURRED);

	// try to set a rowset property through a column, DBPROPOPTIONS_OPTIONAL
	rgColumnDesc[0].cPropertySets	= NUMELEM(rgPropSet);
	rgColumnDesc[0].rgPropertySets	= rgPropSet;
	FILL_PROP_SET(rgPropSet[0], NUMELEM(rgProp), rgProp, DBPROPSET_ROWSET)
	FILL_PROP(rgProp[0], DBPROP_BOOKMARKS, DBTYPE_I4, V_I4, lValue, DBPROPOPTIONS_OPTIONAL)
	TESTC_(CCNDropTable(NULL, cColumnDesc, rgColumnDesc, IID_IRowset, 0, NULL), DB_S_ERRORSOCCURRED);
	
CLEANUP:
	rgColumnDesc[0].cPropertySets		= 0;
	rgColumnDesc[0].rgPropertySets	= NULL;
	ReleaseColumnDesc(rgColumnDesc, cColumnDesc);
	TRETURN
}
// }}


// {{ TCW_VAR_PROTOTYPE(35)
//*-----------------------------------------------------------------------
// @mfunc Invalid column precision => DB_E_BADPRECISION
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCCreateTable::Variation_35()
{
	TBEGIN
	const int		n=8;
	BYTE			testValues[n];
	HRESULT			testResult[n]={S_OK, S_OK, S_OK, S_OK, S_OK, S_OK, DB_E_BADPRECISION, DB_E_BADPRECISION};
	CCol			Col;
	ULONG			cPrecision;
	DBORDINAL		i;
	DBCOLUMNDESC	*rgColumnDesc	= NULL;
	DBORDINAL		cColumnDesc		= 0;

	DuplicateColumnDesc(m_rgColumnDesc, m_cColumnDesc, &rgColumnDesc);
	cColumnDesc = m_cColumnDesc;
	ReleaseAllColumnPropSets(rgColumnDesc, cColumnDesc);

	testValues[0] = 0;
	testValues[1] = 1;
	for (i=0; i<cColumnDesc; i++)
	{
		Col = GetType(GetColumnTypeName(&rgColumnDesc[i]), rgColumnDesc[i].wType);
		ASSERT(0 == wcscmp(Col.GetProviderTypeName(), GetColumnTypeName(&rgColumnDesc[i])));
		
		if (rgColumnDesc[i].wType == DBTYPE_NUMERIC)
			testResult[0] = DB_E_BADPRECISION;
		else
			testResult[0] = S_OK;

		testResult[6] = S_OK;
		testResult[7] = S_OK;
		if (rgColumnDesc[i].wType == DBTYPE_NUMERIC)
			{
				testResult[6] = DB_E_BADPRECISION;
				testResult[7] = DB_E_BADPRECISION;

			}
		testValues[2] = (BYTE)(Col.GetPrecision()/3);
		testValues[3] = (BYTE)(2*Col.GetPrecision()/3);
		testValues[4] = (BYTE)Col.GetPrecision()-1;
		testValues[5] = (BYTE)Col.GetPrecision();
		testValues[6] = (BYTE)Col.GetPrecision()+1;
		testValues[7] = (BYTE)Col.GetPrecision()+10;
		odtLog	<< rgColumnDesc[i].pwszTypeName  <<"  (" 
				<< rgColumnDesc[i].dbcid.uName.pwszName  << ") max precision =" << testValues[5] << "\n";
		odtLog	<< "\t" << "precisions tested :";
		for (cPrecision=0; cPrecision<n; cPrecision++)
			odtLog << "\t" << (ULONG)testValues[cPrecision];
		odtLog << "\n";

		for (cPrecision=0; cPrecision<n; cPrecision++)
		{
			rgColumnDesc[i].bPrecision		= (BYTE)testValues[cPrecision];
			rgColumnDesc[i].ulColumnSize	= 0;
			rgColumnDesc[i].bScale			= 0;

			if (!CHECK(CCNDropTable(NULL, 1, &rgColumnDesc[i], IID_IRowset, 0, NULL), testResult[cPrecision]))
			{
				odtLog << "Error for precision " << testValues[cPrecision] << "\n";
			}		
		}
	}

	ReleaseColumnDesc(rgColumnDesc, cColumnDesc);
	TRETURN
}
// }}


// {{ TCW_VAR_PROTOTYPE(36)
//*-----------------------------------------------------------------------
// @mfunc invalid scale on column => DB_E_BADSCALE
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCCreateTable::Variation_36()
{
	TBEGIN
	const int		n=7;
	BYTE			testValues[n];
	HRESULT			testResult[n]={S_OK, S_OK, S_OK, S_OK, S_OK, DB_E_BADSCALE, DB_E_BADSCALE};
	CCol			Col;
	ULONG			cScale, m;
	DBORDINAL		i;
	DBCOLUMNDESC	*rgColumnDesc	= NULL;
	DBORDINAL		cColumnDesc		= 0;

	DuplicateColumnDesc(m_rgColumnDesc, m_cColumnDesc, &rgColumnDesc);
	cColumnDesc = m_cColumnDesc;
	ReleaseAllColumnPropSets(rgColumnDesc, cColumnDesc);

	testValues[0] = 0;
	testValues[1] = 1;
	for (i=0; i<cColumnDesc; i++)
	{
		Col = GetType(GetColumnTypeName(&rgColumnDesc[i]), rgColumnDesc[i].wType);
		ASSERT(0 == wcscmp(Col.GetProviderTypeName(), GetColumnTypeName(&rgColumnDesc[i])));

		odtLog << rgColumnDesc[i].pwszTypeName << "\n";
		testResult[0] = S_OK;
		testResult[1] = S_OK;
		testValues[0] = 0;
		testValues[1] = 1;
		testValues[2] = 100;
		testValues[3] = (BYTE)Col.GetPrecision()+1;
		m = 4;
		if ((rgColumnDesc[i].wType == DBTYPE_NUMERIC) || (rgColumnDesc[i].wType == DBTYPE_DECIMAL))
		{
			m = 7;
			if (Col.GetMinScale()>0)
			{
				testResult[0] = DB_E_BADSCALE;
				testResult[1] = DB_E_BADSCALE;
			}
			testResult[4] = S_OK;
			testValues[1] = (BYTE)max(Col.GetMinScale()-1, 0);
			testValues[2] = (BYTE)Col.GetMinScale();
			testValues[3] = (BYTE)((Col.GetMinScale()+Col.GetMaxScale())/2);
			testValues[4] = (BYTE)Col.GetMaxScale();
			testValues[5] = (BYTE)Col.GetMaxScale()+1;
			testValues[6] = (BYTE)Col.GetMaxScale();
			// tests
			for (cScale=0; cScale<m; cScale++)
			{
				rgColumnDesc[i].bScale = (BYTE)testValues[cScale];
				if (cScale+1 == m)
				{
					rgColumnDesc[i].bPrecision = max(1, Col.GetMaxScale()-2);
					odtLog	<< "\nprecision: " << rgColumnDesc[i].bPrecision 
							<< ", scale: " << testValues[cScale] <<"\n";
				}
				else
					odtLog << "\t" << testValues[cScale];

				if (!CHECK(CCNDropTable(NULL, 1, &rgColumnDesc[i], IID_IRowset, 0, NULL), testResult[cScale]))
				{
					odtLog << "Error for scale " << testValues[cScale] << "\n";
				}		
			}
			odtLog << "\n";
		}
		else
		{
			testResult[4] = S_OK;
			for (cScale=0; cScale<m; cScale++)
			{
				rgColumnDesc[i].bScale = (BYTE)testValues[cScale];
				if (cScale+1 == m)
					rgColumnDesc[cScale].bPrecision = Col.GetMaxScale()-1;
				
				if (!CHECK(CCNDropTable(NULL, 1, &rgColumnDesc[i], 
							IID_IRowset, 0, NULL), testResult[cScale]))
				{
					odtLog << "Error for scale " << testValues[cScale] << "\n";
				}
			}
		}
	}
	
	ReleaseColumnDesc(rgColumnDesc, cColumnDesc);
	TRETURN
}
// }}


// {{ TCW_VAR_PROTOTYPE(37)
//*-----------------------------------------------------------------------
// @mfunc col prop is not in the Column, Rowset or Table property group and dwOption is DBPROP_SETIFCHEAP => DB_S_ERRORSOCCURRED
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCCreateTable::Variation_37()
{
	TBEGIN
	DBPROPSET		rgPropSet[1];
	DBPROP			rgProp[1];
	DBCOLUMNDESC	*rgColumnDesc	= NULL;
	DBORDINAL		cColumnDesc		= 0;

	DuplicateColumnDesc(m_rgColumnDesc, m_cColumnDesc, &rgColumnDesc);
	cColumnDesc = m_cColumnDesc;
	ReleaseAllColumnPropSets(rgColumnDesc, cColumnDesc);

	// set a column property that doesn't belong to the column, rowset or table propriety group
	rgColumnDesc[0].cPropertySets	= NUMELEM(rgPropSet);
	rgColumnDesc[0].rgPropertySets	= rgPropSet;
	FILL_PROP_SET(rgPropSet[0], NUMELEM(rgProp), rgProp, DBPROPSET_DBINIT)
	FILL_PROP(rgProp[0], DBPROP_AUTH_PASSWORD, DBTYPE_BSTR, V_BSTR, 
		SysAllocString(L"passwd"), DBPROPOPTIONS_OPTIONAL)

	TESTC_(CCNDropTable(NULL, cColumnDesc, rgColumnDesc, IID_IRowset, 0, NULL), DB_S_ERRORSOCCURRED);

CLEANUP:
	SysFreeString(V_BSTR(&rgProp[0].vValue));
	rgColumnDesc[0].cPropertySets		= 0;
	rgColumnDesc[0].rgPropertySets	= NULL;	
	ReleaseColumnDesc(rgColumnDesc, cColumnDesc);
	TRETURN
}
// }}


// {{ TCW_VAR_PROTOTYPE(38)
//*-----------------------------------------------------------------------
// @mfunc col prop is not in the Column, Rowset or Table property group and dwOption is DBPROP_REQUIRED => DB_E_ERRORSOCCURRED
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCCreateTable::Variation_38()
{
	TBEGIN
	DBPROPSET		rgPropSet[1];
	DBPROP			rgProp[1];
	DBCOLUMNDESC	*rgColumnDesc	= NULL;
	DBORDINAL		cColumnDesc		= 0;

	DuplicateColumnDesc(m_rgColumnDesc, m_cColumnDesc, &rgColumnDesc);
	cColumnDesc = m_cColumnDesc;
	ReleaseAllColumnPropSets(rgColumnDesc, cColumnDesc);

	// set a column property ID that is not valid
	rgColumnDesc[0].cPropertySets	= NUMELEM(rgPropSet);
	rgColumnDesc[0].rgPropertySets	= rgPropSet;
	FILL_PROP_SET(rgPropSet[0], NUMELEM(rgProp), rgProp, DBPROPSET_DBINIT)
	FILL_PROP(rgProp[0], DBPROP_AUTH_PASSWORD, DBTYPE_BSTR, V_BSTR, 
		SysAllocString(L"passwd"), DBPROPOPTIONS_REQUIRED)

	TESTC_(CCNDropTable(NULL, cColumnDesc, rgColumnDesc, IID_IRowset, 0, NULL), DB_E_ERRORSOCCURRED);

CLEANUP:
	SysFreeString(V_BSTR(&rgProp[0].vValue));
	rgColumnDesc[0].cPropertySets		= 0;
	rgColumnDesc[0].rgPropertySets	= NULL;	
	ReleaseColumnDesc(rgColumnDesc, cColumnDesc);
	TRETURN
}
// }}


// {{ TCW_VAR_PROTOTYPE(39)
//*-----------------------------------------------------------------------
// @mfunc invalid propID for a column propriety
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCCreateTable::Variation_39()
{
	TBEGIN
	DBPROPSET		rgPropSet[1];
	DBPROP			rgProp[1];
	DBCOLUMNDESC	*rgColumnDesc	= NULL;
	DBORDINAL		cColumnDesc		= 0;

	DuplicateColumnDesc(m_rgColumnDesc, m_cColumnDesc, &rgColumnDesc);
	cColumnDesc = m_cColumnDesc;
	ReleaseAllColumnPropSets(rgColumnDesc, cColumnDesc);

	// set an inexistent column property with DBPROPOPTIONS_OPTIONAL
	rgColumnDesc[0].cPropertySets	= NUMELEM(rgPropSet);
	rgColumnDesc[0].rgPropertySets	= rgPropSet;
	FILL_PROP_SET(rgPropSet[0], 1, rgProp, DBPROPSET_COLUMN)
	FILL_PROP(rgProp[0], 0xffff, DBTYPE_I4, V_I4, 42, DBPROPOPTIONS_OPTIONAL)
	CHECK(CCNDropTable(NULL, cColumnDesc, rgColumnDesc, IID_IRowset, 0, NULL), DB_S_ERRORSOCCURRED);

	// set an inexistent column property with DBPROPOPTIONS_REQUIRED
	rgColumnDesc[0].cPropertySets	= NUMELEM(rgPropSet);
	rgColumnDesc[0].rgPropertySets	= rgPropSet;
	FILL_PROP_SET(rgPropSet[0], 1, rgProp, DBPROPSET_COLUMN)
	FILL_PROP(rgProp[0], 0xffff, DBTYPE_I4, V_I4, 42, DBPROPOPTIONS_REQUIRED)

	TESTC_(CCNDropTable(NULL, cColumnDesc, rgColumnDesc, IID_IRowset, 0, NULL), DB_E_ERRORSOCCURRED);

CLEANUP:
	rgColumnDesc[0].cPropertySets = 0;
	rgColumnDesc[0].rgPropertySets = NULL;
	ReleaseColumnDesc(rgColumnDesc, cColumnDesc);
	TRETURN
}
// }}


// {{ TCW_VAR_PROTOTYPE(40)
//*-----------------------------------------------------------------------
// @mfunc colid in DBPROP of a column property is ignored
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCCreateTable::Variation_40()
{
	TBEGIN
	DBPROPSET		rgPropSet[1];
	DBPROP			rgProp[1];
	DBCOLUMNDESC	*rgColumnDesc	= NULL;
	DBORDINAL		cColumnDesc		= 0;
	DBPROPID		rgPropID[]		= {	DBPROP_COL_AUTOINCREMENT, DBPROP_COL_NULLABLE};
	ULONG			i;

	DuplicateColumnDesc(m_rgColumnDesc, m_cColumnDesc, &rgColumnDesc);
	cColumnDesc = m_cColumnDesc;
	ReleaseAllColumnPropSets(rgColumnDesc, cColumnDesc);

	rgColumnDesc[0].cPropertySets	= 0;
	rgColumnDesc[0].rgPropertySets	= NULL;

	// set a column property that is not ...
	for (i=0; i<NUMELEM(rgPropID); i++)
	{
		if (SettableProperty(rgPropID[i], DBPROPSET_COLUMN))
			break;
	}
	TESTC_PROVIDER(i<NUMELEM(rgPropID));

	rgColumnDesc[0].cPropertySets	= 1;
	rgColumnDesc[0].rgPropertySets	= rgPropSet;
	FILL_PROP_SET(rgPropSet[0], 1, rgProp, DBPROPSET_COLUMN)
	FILL_PROP(rgProp[0], rgPropID[i], DBTYPE_BOOL, V_BOOL, 
		VARIANT_TRUE, DBPROPOPTIONS_OPTIONAL)

	// set colID to a value different from DB_NULLID	
	rgProp[0].colid.eKind			= DBKIND_NAME;
	rgProp[0].colid.uName.pwszName	= wcsDuplicate(L"someColumn");

	// check colid is ignored for the column property
	CHECK(CCNDropTable(NULL, cColumnDesc, rgColumnDesc, IID_IRowset, 0, NULL), S_OK);
	COMPARE(DBPROPSTATUS_OK == rgProp[0].dwStatus, TRUE);

	// check colid is ignored for the column property
	rgProp[0].dwOptions = DBPROPOPTIONS_REQUIRED;
	CHECK(CCNDropTable(NULL, cColumnDesc, rgColumnDesc, IID_IRowset, 0, NULL), S_OK);
	COMPARE(DBPROPSTATUS_OK == rgProp[0].dwStatus, TRUE);

CLEANUP:
	PROVIDER_FREE(rgProp[0].colid.uName.pwszName);
	rgColumnDesc[0].cPropertySets		= 0;
	rgColumnDesc[0].rgPropertySets	= NULL;	
	ReleaseColumnDesc(rgColumnDesc, cColumnDesc);
	TRETURN
}
// }}


// {{ TCW_VAR_PROTOTYPE(41)
//*-----------------------------------------------------------------------
// @mfunc Abort retaining
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCCreateTable::Variation_41()
{ 
	TBEGIN
	BOOL				fExists;
	ITransactionLocal	*pITransactionLocal = NULL;
	DBID				*pTableID = NULL;
	DBPROPSET			*rgPropSet = NULL;
	ULONG				cPropSet = 0;
	IRowsetInfo			*pIRowsetInfo = NULL;
	BOOL				fAbortPreserve = TRUE;
	ULONG				cReadPropSet = 0;
	DBPROPSET			*rgReadPropSet = NULL;
	DBCOLUMNDESC		*rgColumnDesc	= NULL;
	DBORDINAL			cColumnDesc		= 0;
	VARIANT				vSupportedTxnDDL;
	HRESULT				hr;

	TESTC_PROVIDER(VerifyInterface(m_pITableDefinition, IID_ITransactionLocal,
		SESSION_INTERFACE, (IUnknown**)&pITransactionLocal));

	VariantInit(&vSupportedTxnDDL);
	TESTC_PROVIDER(GetProperty(DBPROP_SUPPORTEDTXNDDL, DBPROPSET_DATASOURCEINFO, 
			g_pIDBInitialize, &vSupportedTxnDDL));
	
	TESTC(VT_I4 == vSupportedTxnDDL.vt);
	// what values should we accept?
	TESTC_PROVIDER(DBPROPVAL_TC_NONE != vSupportedTxnDDL.lVal);

	DuplicateColumnDesc(m_rgColumnDesc, m_cColumnDesc, &rgColumnDesc);
	cColumnDesc = m_cColumnDesc;
	ReleaseAllColumnPropSets(rgColumnDesc, cColumnDesc);

	TESTC_(StartTransaction(pITransactionLocal), S_OK);

	// if possible, prepare to ask DBPROP_ABORTPRESERVE to be set to VARIANT_FALSE
	if (SettableProperty(DBPROP_ABORTPRESERVE, DBPROPSET_ROWSET))
	{
		::SetProperty(DBPROP_ABORTPRESERVE, DBPROPSET_ROWSET, &cPropSet, &rgPropSet, 
			(LPVOID)VARIANT_FALSE, VT_BOOL, DBPROPOPTIONS_REQUIRED, DB_NULLID);
	}

	switch(vSupportedTxnDDL.lVal)
	{
		case DBPROPVAL_TC_DML:
			//check for XACT_E_XTIONEXISTS
			CHECK(hr = m_pITableDefinition->CreateTable(NULL, NULL, cColumnDesc, rgColumnDesc,
				IID_IRowsetInfo, cPropSet, rgPropSet, &pTableID,
				(IUnknown**)&pIRowsetInfo), XACT_E_XTIONEXISTS);
			break;

		case DBPROPVAL_TC_DDL_IGNORE:
			// the statement is not transacted
		case DBPROPVAL_TC_ALL:
		case DBPROPVAL_TC_DDL_COMMIT:
			CHECK(hr = CreateAndCheckTable(m_pITableDefinition, NULL, NULL, 
				cColumnDesc, rgColumnDesc, IID_IRowsetInfo, 
				cPropSet, rgPropSet, &pTableID, 
				(IUnknown**)&pIRowsetInfo), S_OK);
			break;

		case DBPROPVAL_TC_DDL_LOCK:
			// error should be returned
			CHECK(hr = m_pITableDefinition->CreateTable(NULL, NULL, cColumnDesc, rgColumnDesc,
				IID_IRowsetInfo, cPropSet, rgPropSet, &pTableID,
				(IUnknown**)&pIRowsetInfo), S_OK);
			break;
			
		default:
			TESTC(FALSE);
	}

	if (DBPROPVAL_TC_DDL_COMMIT != vSupportedTxnDDL.lVal)
	{
		if (pIRowsetInfo)
			fAbortPreserve = GetProperty(DBPROP_ABORTPRESERVE, DBPROPSET_ROWSET, pIRowsetInfo, VARIANT_TRUE);
		// abort retaining
		CHECK(pITransactionLocal->Abort(NULL, TRUE, FALSE), S_OK);
		// check that it is retaining (another transaction is available)
		CHECK(m_hr = pITransactionLocal->Abort(NULL, FALSE, FALSE), S_OK);
	}

	// abort retaining and check that the table doesn't exist anymore
	CHECK(m_hr = m_pTable->DoesTableExist(pTableID, &fExists), S_OK);
	COMPARE(fExists, DBPROPVAL_TC_DDL_IGNORE == vSupportedTxnDDL.lVal
		|| DBPROPVAL_TC_DDL_COMMIT == vSupportedTxnDDL.lVal);
	if (fExists)
	{
		CHECK(DropTableAndCheck(pTableID), S_OK);
	}

	// test zombie rowset
	if (pIRowsetInfo)
		TESTC_(pIRowsetInfo->GetProperties(0, NULL, &cReadPropSet, &rgReadPropSet), fAbortPreserve? S_OK: E_UNEXPECTED);

CLEANUP:
	SAFE_RELEASE(pITransactionLocal);
	SAFE_RELEASE(pIRowsetInfo);
	ReleaseDBID(pTableID);
	FreeProperties( &cPropSet, &rgPropSet);
	FreeProperties( &cReadPropSet, &rgReadPropSet);
	ReleaseColumnDesc(rgColumnDesc, cColumnDesc);
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(42)
//*-----------------------------------------------------------------------
// @mfunc Abort without retaining
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCCreateTable::Variation_42()
{ 
	TBEGIN
	BOOL				fExists;
	ITransactionLocal	*pITransactionLocal = NULL;
	DBID				*pTableID = NULL;
	DBPROPSET			*rgPropSet = NULL;
	ULONG				cPropSet = 0;
	IRowsetInfo			*pIRowsetInfo = NULL;
	BOOL				fAbortPreserve = TRUE;
	ULONG				cReadPropSet = 0;
	DBPROPSET			*rgReadPropSet = NULL;
	DBCOLUMNDESC		*rgColumnDesc	= NULL;
	DBORDINAL			cColumnDesc		= 0;
	VARIANT				vSupportedTxnDDL;

	TESTC_PROVIDER(VerifyInterface(m_pITableDefinition, IID_ITransactionLocal,
		SESSION_INTERFACE, (IUnknown**)&pITransactionLocal));

	VariantInit(&vSupportedTxnDDL);
	TESTC_PROVIDER(GetProperty(DBPROP_SUPPORTEDTXNDDL, DBPROPSET_DATASOURCEINFO, 
			g_pIDBInitialize, &vSupportedTxnDDL));
	
	TESTC(VT_I4 == vSupportedTxnDDL.vt);
	// what values should we accept?
	TESTC_PROVIDER(DBPROPVAL_TC_NONE != vSupportedTxnDDL.lVal);

	DuplicateColumnDesc(m_rgColumnDesc, m_cColumnDesc, &rgColumnDesc);
	cColumnDesc = m_cColumnDesc;
	ReleaseAllColumnPropSets(rgColumnDesc, cColumnDesc);

	TESTC_(StartTransaction(pITransactionLocal), S_OK);

	// if possible, prepare to ask DBPROP_ABORTPRESERVE to be set to VARIANT_FALSE
	if (SettableProperty(DBPROP_ABORTPRESERVE, DBPROPSET_ROWSET))
	{
		::SetProperty(DBPROP_ABORTPRESERVE, DBPROPSET_ROWSET, &cPropSet, &rgPropSet, 
			(LPVOID)VARIANT_FALSE, VT_BOOL, DBPROPOPTIONS_REQUIRED, DB_NULLID);
	}
	
	switch(vSupportedTxnDDL.lVal)
	{
		case DBPROPVAL_TC_DML:
			//check for XACT_E_XTIONEXISTS
			CHECK(m_hr = m_pITableDefinition->CreateTable(NULL, NULL, cColumnDesc, rgColumnDesc,
				IID_IRowsetInfo, cPropSet, rgPropSet, &pTableID,
				(IUnknown**)&pIRowsetInfo), XACT_E_XTIONEXISTS);
			break;

		case DBPROPVAL_TC_DDL_IGNORE:
			// the statement is not transacted
		case DBPROPVAL_TC_ALL:
		case DBPROPVAL_TC_DDL_COMMIT:
			CHECK(CreateAndCheckTable(m_pITableDefinition, NULL, NULL, 
				cColumnDesc, rgColumnDesc, IID_IRowsetInfo, 
				cPropSet, rgPropSet, &pTableID, 
				(IUnknown**)&pIRowsetInfo), S_OK);
			break;

		case DBPROPVAL_TC_DDL_LOCK:
			// error should be returned
			CHECK(m_hr = m_pITableDefinition->CreateTable(NULL, NULL, cColumnDesc, rgColumnDesc,
				IID_IRowsetInfo, cPropSet, rgPropSet, &pTableID,
				(IUnknown**)&pIRowsetInfo), S_OK);
			break;
			
		default:
			TESTC(FALSE);
	}

	if (DBPROPVAL_TC_DDL_COMMIT != vSupportedTxnDDL.lVal)
	{
		fAbortPreserve = GetProperty(DBPROP_ABORTPRESERVE, DBPROPSET_ROWSET, pIRowsetInfo, VARIANT_TRUE);
		// abort non retaining
		CHECK(m_hr = pITransactionLocal->Abort(NULL, FALSE, FALSE), S_OK);
		// check that it is retaining (another transaction is available)
		CHECK(pITransactionLocal->Abort(NULL, FALSE, FALSE), 
			FAILED(m_hr)? S_OK : XACT_E_NOTRANSACTION);
	}

	// abort retaining and check that the table doesn't exist anymore
	CHECK(m_hr = m_pTable->DoesTableExist(pTableID, &fExists), S_OK);
	COMPARE(fExists, DBPROPVAL_TC_DDL_IGNORE == vSupportedTxnDDL.lVal
		|| DBPROPVAL_TC_DDL_COMMIT == vSupportedTxnDDL.lVal);
	if (fExists)
	{
		CHECK(DropTableAndCheck(pTableID), S_OK);
	}

	// test zombie rowset
	TESTC_(pIRowsetInfo->GetProperties(0, NULL, &cReadPropSet, &rgReadPropSet), fAbortPreserve? S_OK: E_UNEXPECTED);

CLEANUP:
	SAFE_RELEASE(pITransactionLocal);
	SAFE_RELEASE(pIRowsetInfo);
	ReleaseDBID(pTableID);
	FreeProperties( &cPropSet, &rgPropSet);
	FreeProperties(&cReadPropSet, &rgReadPropSet);
	ReleaseColumnDesc(rgColumnDesc, cColumnDesc);
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(43)
//*-----------------------------------------------------------------------
// @mfunc Commit retain
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCCreateTable::Variation_43()
{ 
	TBEGIN
	BOOL				fExists;
	ITransactionLocal	*pITransactionLocal = NULL;
	DBID				*pTableID = NULL;
	DBPROPSET			*rgPropSet = NULL;
	ULONG				cPropSet = 0;
	IRowsetInfo			*pIRowsetInfo = NULL;
	BOOL				fCommitPreserve = TRUE;
	ULONG				cReadPropSet = 0;
	DBPROPSET			*rgReadPropSet = NULL;
	DBCOLUMNDESC		*rgColumnDesc	= NULL;
	DBORDINAL			cColumnDesc		= 0;
	VARIANT				vSupportedTxnDDL;

	TESTC_PROVIDER(VerifyInterface(m_pITableDefinition, IID_ITransactionLocal,
		SESSION_INTERFACE, (IUnknown**)&pITransactionLocal));

	VariantInit(&vSupportedTxnDDL);
	TESTC_PROVIDER(GetProperty(DBPROP_SUPPORTEDTXNDDL, DBPROPSET_DATASOURCEINFO, 
			g_pIDBInitialize, &vSupportedTxnDDL));
	
	TESTC(VT_I4 == vSupportedTxnDDL.vt);
	// what values should we accept?
	TESTC_PROVIDER(DBPROPVAL_TC_NONE != vSupportedTxnDDL.lVal);

	DuplicateColumnDesc(m_rgColumnDesc, m_cColumnDesc, &rgColumnDesc);
	cColumnDesc = m_cColumnDesc;
	ReleaseAllColumnPropSets(rgColumnDesc, cColumnDesc);

	TESTC_(StartTransaction(pITransactionLocal), S_OK);

	// if possible, prepare to ask DBPROP_ABORTPRESERVE to be set to VARIANT_FALSE
	if (SettableProperty(DBPROP_COMMITPRESERVE, DBPROPSET_ROWSET))
	{
		::SetProperty(DBPROP_COMMITPRESERVE, DBPROPSET_ROWSET, &cPropSet, &rgPropSet, 
			(LPVOID)VARIANT_FALSE, VT_BOOL, DBPROPOPTIONS_REQUIRED, DB_NULLID);
	}
	
	switch(vSupportedTxnDDL.lVal)
	{
		case DBPROPVAL_TC_DML:
			//check for XACT_E_XTIONEXISTS
			CHECK(m_hr = m_pITableDefinition->CreateTable(NULL, NULL, cColumnDesc, rgColumnDesc,
				IID_IRowsetInfo, cPropSet, rgPropSet, &pTableID,
				(IUnknown**)&pIRowsetInfo), XACT_E_XTIONEXISTS);
			break;

		case DBPROPVAL_TC_DDL_IGNORE:
			// the statement is not transacted
		case DBPROPVAL_TC_ALL:
		case DBPROPVAL_TC_DDL_COMMIT:
			CHECK(CreateAndCheckTable(m_pITableDefinition, NULL, NULL, 
				cColumnDesc, rgColumnDesc, IID_IRowsetInfo, 
				cPropSet, rgPropSet, &pTableID, 
				(IUnknown**)&pIRowsetInfo), S_OK);
			break;

		case DBPROPVAL_TC_DDL_LOCK:
			// error should be returned
			CHECK(m_hr = m_pITableDefinition->CreateTable(NULL, NULL, cColumnDesc, rgColumnDesc,
				IID_IRowsetInfo, cPropSet, rgPropSet, &pTableID,
				(IUnknown**)&pIRowsetInfo), S_OK);
			break;
			
		default:
			TESTC(FALSE);
	}

	if (DBPROPVAL_TC_DDL_COMMIT != vSupportedTxnDDL.lVal)
	{
		fCommitPreserve = GetProperty(DBPROP_COMMITPRESERVE, DBPROPSET_ROWSET, pIRowsetInfo, VARIANT_TRUE);
		// commit retaining
		CHECK(m_hr = pITransactionLocal->Commit(TRUE, 0, 0), S_OK);
		// check that it is retaining (another transaction is available)
		CHECK(m_hr = pITransactionLocal->Abort(NULL, FALSE, FALSE), S_OK);
	}

	// abort retaining and check that the table doesn't exist anymore
	CHECK(m_hr = m_pTable->DoesTableExist(pTableID, &fExists), S_OK);
	COMPARE(fExists, DBPROPVAL_TC_DML != vSupportedTxnDDL.lVal);
	if (fExists)
	{
		CHECK(DropTableAndCheck(pTableID), S_OK);
	}

	// test zombie rowset
	TESTC_(pIRowsetInfo->GetProperties(0, NULL, &cReadPropSet, &rgReadPropSet), fCommitPreserve? S_OK: E_UNEXPECTED);
	
CLEANUP:
	SAFE_RELEASE(pITransactionLocal);
	SAFE_RELEASE(pIRowsetInfo);
	DropTableAndCheck(pTableID);
	ReleaseDBID(pTableID);
	FreeProperties( &cPropSet, &rgPropSet);
	FreeProperties(&cReadPropSet, &rgReadPropSet);
	ReleaseColumnDesc(rgColumnDesc, cColumnDesc);
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(44)
//*-----------------------------------------------------------------------
// @mfunc Commit non-retaining
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCCreateTable::Variation_44()
{ 
	TBEGIN
	BOOL				fExists;
	ITransactionLocal	*pITransactionLocal = NULL;
	DBID				*pTableID = NULL;
	DBPROPSET			*rgPropSet = NULL;
	ULONG				cPropSet = 0;
	IRowsetInfo			*pIRowsetInfo = NULL;
	BOOL				fCommitPreserve = TRUE;
	ULONG				cReadPropSet = 0;
	DBPROPSET			*rgReadPropSet = NULL;
	DBCOLUMNDESC		*rgColumnDesc	= NULL;
	DBORDINAL			cColumnDesc		= 0;
	VARIANT				vSupportedTxnDDL;

	TESTC_PROVIDER(VerifyInterface(m_pITableDefinition, IID_ITransactionLocal,
		SESSION_INTERFACE, (IUnknown**)&pITransactionLocal));

	VariantInit(&vSupportedTxnDDL);
	TESTC_PROVIDER(GetProperty(DBPROP_SUPPORTEDTXNDDL, DBPROPSET_DATASOURCEINFO, 
			g_pIDBInitialize, &vSupportedTxnDDL));
	
	TESTC(VT_I4 == vSupportedTxnDDL.vt);
	// what values should we accept?
	TESTC_PROVIDER(DBPROPVAL_TC_NONE != vSupportedTxnDDL.lVal);

	DuplicateColumnDesc(m_rgColumnDesc, m_cColumnDesc, &rgColumnDesc);
	cColumnDesc = m_cColumnDesc;
	ReleaseAllColumnPropSets(rgColumnDesc, cColumnDesc);

	TESTC_(StartTransaction(pITransactionLocal), S_OK);

	// if possible, prepare to ask DBPROP_ABORTPRESERVE to be set to VARIANT_FALSE
	if (SettableProperty(DBPROP_COMMITPRESERVE, DBPROPSET_ROWSET))
	{
		::SetProperty(DBPROP_COMMITPRESERVE, DBPROPSET_ROWSET, &cPropSet, &rgPropSet, 
			(LPVOID)VARIANT_FALSE, VT_BOOL, DBPROPOPTIONS_REQUIRED, DB_NULLID);
	}
	
	switch(vSupportedTxnDDL.lVal)
	{
		case DBPROPVAL_TC_DML:
			//check for XACT_E_XTIONEXISTS
			CHECK(m_hr = m_pITableDefinition->CreateTable(NULL, NULL, cColumnDesc, rgColumnDesc,
				IID_IRowsetInfo, cPropSet, rgPropSet, &pTableID,
				(IUnknown**)&pIRowsetInfo), XACT_E_XTIONEXISTS);
			break;

		case DBPROPVAL_TC_DDL_IGNORE:
			// the statement is not transacted
		case DBPROPVAL_TC_ALL:
		case DBPROPVAL_TC_DDL_COMMIT:
			CHECK(CreateAndCheckTable(m_pITableDefinition, NULL, NULL, 
				cColumnDesc, rgColumnDesc, IID_IRowsetInfo, 
				cPropSet, rgPropSet, &pTableID, 
				(IUnknown**)&pIRowsetInfo), S_OK);
			break;

		case DBPROPVAL_TC_DDL_LOCK:
			// error should be returned
			CHECK(m_hr = m_pITableDefinition->CreateTable(NULL, NULL, cColumnDesc, rgColumnDesc,
				IID_IRowsetInfo, cPropSet, rgPropSet, &pTableID,
				(IUnknown**)&pIRowsetInfo), S_OK);
			break;
			
		default:
			TESTC(FALSE);
	}

	if (DBPROPVAL_TC_DDL_COMMIT != vSupportedTxnDDL.lVal)
	{
		fCommitPreserve = GetProperty(DBPROP_COMMITPRESERVE, DBPROPSET_ROWSET, pIRowsetInfo, VARIANT_TRUE);
		// commit non retaining
		CHECK(m_hr = pITransactionLocal->Commit(FALSE, 0, 0), S_OK);
		// check that it is retaining (another transaction is available)
		CHECK(pITransactionLocal->Abort(NULL, FALSE, FALSE), 
			FAILED(m_hr)? S_OK: XACT_E_NOTRANSACTION);
	}

	// abort retaining and check that the table doesn't exist anymore
	CHECK(m_hr = m_pTable->DoesTableExist(pTableID, &fExists), S_OK);
	COMPARE(fExists, DBPROPVAL_TC_DML != vSupportedTxnDDL.lVal);
	if (fExists)
	{
		CHECK(DropTableAndCheck(pTableID), S_OK);
		goto CLEANUP;
	}

	// test zombie rowset
	TESTC_(pIRowsetInfo->GetProperties(0, NULL, &cReadPropSet, &rgReadPropSet), fCommitPreserve? S_OK: E_UNEXPECTED);
	
CLEANUP:
	SAFE_RELEASE(pITransactionLocal);
	SAFE_RELEASE(pIRowsetInfo);
	DropTableAndCheck(pTableID);
	ReleaseDBID(pTableID);
	FreeProperties( &cPropSet, &rgPropSet);
	FreeProperties(&cReadPropSet, &rgReadPropSet);
	ReleaseColumnDesc(rgColumnDesc, cColumnDesc);
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(45)
//*-----------------------------------------------------------------------
// @mfunc Autoincrementable columns
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCCreateTable::Variation_45()
{ 
	TBEGIN
	DBORDINAL		i;
	HRESULT			resA, resB;
	CCol			col;
	BOOL			fReadWriteAutoInc;
	HRESULT			hr;
	DBCOLUMNDESC	*rgColumnDesc	= NULL;
	DBORDINAL		cColumnDesc		= 0;
	ULONG			cPropSet, cProp;

	fReadWriteAutoInc = (GetPropInfoFlags(DBPROP_COL_AUTOINCREMENT, DBPROPSET_COLUMN, 
			m_pThisTestModule->m_pIUnknown, DATASOURCE_INTERFACE) & DBPROPFLAGS_WRITE);

	DuplicateColumnDesc(m_rgColumnDesc, m_cColumnDesc, &rgColumnDesc);
	cColumnDesc = m_cColumnDesc;
	ReleaseAllColumnPropSets(rgColumnDesc, cColumnDesc);
	//SetZeroColSize(rgColumnDesc, cColumnDesc);

	// try all data types
	for (i=0; i<cColumnDesc; i++)
	{
		odtLog << "Type " << GetColumnTypeName(&rgColumnDesc[i]) << "\n";
		// try to create a table in which column rgColumnDesc[i].pwszTypeName is:
		// a) autoincrementable
		// b) not autoincrementable
		col = GetType(GetColumnTypeName(&rgColumnDesc[i]), rgColumnDesc[i].wType);
		resA = col.CanAutoInc()? S_OK: DB_E_ERRORSOCCURRED;
		resB = !col.CanAutoInc() || fReadWriteAutoInc? S_OK : DB_E_ERRORSOCCURRED;

		// create a table with an autoincrementable column
		rgColumnDesc[i].bScale			= 0;
		SetProperty(&rgColumnDesc[i].rgPropertySets, &rgColumnDesc[i].cPropertySets, DBPROP_COL_AUTOINCREMENT,
					VT_BOOL, (LPVOID)VARIANT_TRUE, DBPROPOPTIONS_REQUIRED, DB_NULLID,
					DBPROPSET_COLUMN, &cPropSet, &cProp);

		CHECK(hr = CCNDropTable(NULL, cColumnDesc, rgColumnDesc, IID_IRowset, 
			0, NULL), resA);

		if (S_OK == hr)
		{
			COMPARE(rgColumnDesc[i].rgPropertySets[cPropSet].rgProperties[cProp].dwStatus, DBPROPSTATUS_OK);
		}
		else
		{
			CHECK(hr, DB_E_ERRORSOCCURRED);

			if (!fReadWriteAutoInc && !col.CanAutoInc())
				COMPARE(rgColumnDesc[i].rgPropertySets[0].rgProperties[0].dwStatus, DBPROPSTATUS_NOTSETTABLE);
		}

		odtLog << ((hr == S_OK) ? "\tcolumn added for DBPROPCOL_AUTOINCREMENT set to VARIANT_TRUE\n":
			"\tcolumn NOT added for DBPROPCOL_AUTOINCREMENT set to VARIANT_TRUE\n");
		ReleaseAllColumnPropSets(&rgColumnDesc[i], 1);

		// create a table with a column property value to VARIANT_FALSE for DBPROP_COL_AUTOINCREMENT
		SetProperty(&rgColumnDesc[i].rgPropertySets, &rgColumnDesc[i].cPropertySets, DBPROP_COL_AUTOINCREMENT,
					VT_BOOL, (LPVOID)VARIANT_FALSE, DBPROPOPTIONS_REQUIRED, DB_NULLID,
					DBPROPSET_COLUMN, &cPropSet, &cProp);

		CHECK(CCNDropTable(NULL, cColumnDesc, rgColumnDesc, IID_IRowset, 0, NULL), resB);

		odtLog << ((S_OK == hr) ? "\tcolumn added for DBPROPCOL_AUTOINCREMENT set to VARIANT_FALSE\n":
			"\tcolumn NOT added for DBPROPCOL_AUTOINCREMENT set to VARIANT_FALSE\n");
		ReleaseAllColumnPropSets(&rgColumnDesc[i], 1);
	}

	ReleaseColumnDesc(rgColumnDesc, cColumnDesc);
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(46)
//*-----------------------------------------------------------------------
// @mfunc Default values
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCCreateTable::Variation_46()
{ 
	TBEGIN
	DBORDINAL				i;
	CCol					col;
	VARIANT					value;
	DBCOLUMNDESC			*rgColumnDesc	= NULL;
	DBORDINAL				cColumnDesc		= 0;
	CTable					*pTable = new CTable(m_pThisTestModule->m_pIUnknown2, (LPWSTR)gwszModuleName);
	CList<WCHAR *,WCHAR *>	NativeTypesList;
	CList<DBTYPE,DBTYPE>	ProviderTypesList;
	BOOL					fSettable = TRUE;
	BOOL					fSupported = TRUE;
	HRESULT					hr;
	ULONG					cPropSet, cProp;

	if (!SupportedProperty(DBPROP_COL_DEFAULT, DBPROPSET_COLUMN))
	{
		fSettable	= FALSE;
		fSupported	= FALSE;
	}
	else
		if (!SettableProperty(DBPROP_COL_DEFAULT, DBPROPSET_COLUMN))
			fSettable = FALSE;

	pTable->CreateTypeColInfo(NativeTypesList, ProviderTypesList);
	DuplicateColumnDesc(m_rgColumnDesc, m_cColumnDesc, &rgColumnDesc);
	cColumnDesc = m_cColumnDesc;
	ReleaseAllColumnPropSets(rgColumnDesc, cColumnDesc);

	for (i=0; i<cColumnDesc; i++)
	{
		odtLog << "Type " << GetColumnTypeName(&rgColumnDesc[i]) << "\n";

		// try to create a table in which column rgColumnDesc[i].pwszTypeName has a default value
		col = GetType(GetColumnTypeName(&rgColumnDesc[i]), rgColumnDesc[i].wType);

		// create a table with a default value column
		VariantInit(&value);
		GetDefaultValue(&rgColumnDesc[i], &value, pTable);
		SetDefaultProperty(&rgColumnDesc[i].rgPropertySets, &rgColumnDesc[i].cPropertySets,
			&value, DBPROPOPTIONS_REQUIRED, DB_NULLID, DBPROPSET_COLUMN, &cPropSet, &cProp);	// might be not supported
		VariantClear(&value);

		hr = CCNDropTable(NULL, cColumnDesc, rgColumnDesc, IID_IRowset,	0, NULL);

		if (S_OK == hr)
		{
			COMPARE(rgColumnDesc[i].rgPropertySets[0].rgProperties[0].dwStatus, DBPROPSTATUS_OK);
		}
		else
		{
			odtLog << "Failed on creating a table with a DBPROP_COL_DEFAULT property value set for this type.\n";
			CHECK(hr, DB_E_ERRORSOCCURRED);

			if (!fSupported)
			{
				COMPARE(rgColumnDesc[i].rgPropertySets[cPropSet].rgProperties[cProp].dwStatus, DBPROPSTATUS_NOTSUPPORTED);
			}
			else
				if (!fSettable)
				{
					COMPARE(rgColumnDesc[i].rgPropertySets[cPropSet].rgProperties[cProp].dwStatus, DBPROPSTATUS_BADVALUE);
				}
				else
					COMPARE(rgColumnDesc[i].rgPropertySets[cPropSet].rgProperties[cProp].dwStatus, DBPROPSTATUS_BADVALUE);
		}

		ReleaseAllColumnPropSets(&rgColumnDesc[i], 1);
	}

	ReleaseColumnDesc(rgColumnDesc, cColumnDesc);
	delete pTable;
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(47)
//*-----------------------------------------------------------------------
// @mfunc Column descriptions
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCCreateTable::Variation_47()
{ 
	TBEGIN
	DBORDINAL		i;
	CCol			col;
	HRESULT			hr;
	DBCOLUMNDESC	*rgColumnDesc	= NULL;
	DBORDINAL		cColumnDesc		= 0;

	DuplicateColumnDesc(m_rgColumnDesc, m_cColumnDesc, &rgColumnDesc);
	cColumnDesc = m_cColumnDesc;
	ReleaseAllColumnPropSets(rgColumnDesc, cColumnDesc);
	//SetZeroColSize(rgColumnDesc, cColumnDesc);
	for (i=0; i<cColumnDesc; i++)
	{
		odtLog << "Type " << GetColumnTypeName(&rgColumnDesc[i]) << "\n";
		// try to create a table in which column rgColumnDesc[i].pwszTypeName has a description
		col = GetType(GetColumnTypeName(&rgColumnDesc[i]), rgColumnDesc[i].wType);

		// create a table with a described column
		SetProperty(&rgColumnDesc[i].rgPropertySets, &rgColumnDesc[i].cPropertySets, DBPROP_COL_DESCRIPTION,
					VT_BSTR, (LPVOID)L"description");

		hr = CCNDropTable(NULL, cColumnDesc, rgColumnDesc, IID_IRowset, 0, NULL);

		if (S_OK != hr && !CHECK(hr, DB_S_ERRORSOCCURRED))
		{
			odtLog << "Could not create a table with DBPROP_COL_DESCRIPTION property value set for this type.\n";
		}
		else
		{
			if (DB_S_ERRORSOCCURRED == hr)
				odtLog << "DB_S_ERRORSOCCURRED\n";
		}
		
		ReleaseAllColumnPropSets(&rgColumnDesc[i], 1);
	}
	ReleaseColumnDesc(rgColumnDesc, cColumnDesc);
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(48)
//*-----------------------------------------------------------------------
// @mfunc Variable length columns
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCCreateTable::Variation_48()
{ 
	TBEGIN
	DBORDINAL		i;
	VARIANT			value;
	CCol			col;
	HRESULT			hr;
	DBCOLUMNDESC	*rgColumnDesc	= NULL;
	DBORDINAL		cColumnDesc		= 0;

	value.vt = VT_BOOL;
	DuplicateColumnDesc(m_rgColumnDesc, m_cColumnDesc, &rgColumnDesc);
	cColumnDesc = m_cColumnDesc;
	ReleaseAllColumnPropSets(rgColumnDesc, cColumnDesc);
	//SetZeroColSize(rgColumnDesc, cColumnDesc);

	for (i=0; i<cColumnDesc; i++)
	{
		if (	DBTYPE_STR != rgColumnDesc[i].wType
			&&	DBTYPE_WSTR != rgColumnDesc[i].wType
			&&	DBTYPE_BYTES != rgColumnDesc[i].wType)
			continue;

		odtLog << "Type " << rgColumnDesc[i].pwszTypeName << "\n";
		// try to create a table in which column rgColumnDesc[i].pwszTypeName is:
		// a) fixed length
		// b) variable length
		col = GetType(GetColumnTypeName(&rgColumnDesc[i]), rgColumnDesc[i].wType);

		// create a table with an fixed length column
		SetProperty(&rgColumnDesc[i].rgPropertySets, &rgColumnDesc[i].cPropertySets, DBPROP_COL_FIXEDLENGTH,
					VT_BOOL, (LPVOID)VARIANT_TRUE);
		odtLog	<< "\ttry to create a table with a fixed length column of type " 
				<< rgColumnDesc[i].pwszTypeName << "\n";
		
		hr = CCNDropTable(NULL, cColumnDesc, rgColumnDesc, IID_IRowset, 0, NULL);

		if (S_OK != hr && !CHECK(hr, DB_S_ERRORSOCCURRED))
		{
			odtLog << "\t\tProblems in creating a table with DBPROP_COL_FIXEDLENGTH property value set to VARIANT_TRUE for this column.\n";
		}
		FreeProperties( &rgColumnDesc[i].cPropertySets, &rgColumnDesc[i].rgPropertySets);
		
		// create a table with a column property value set to VARIANT_FALSE for DBPROP_COL_FIXEDLENGTH
		SetProperty(&rgColumnDesc[i].rgPropertySets, &rgColumnDesc[i].cPropertySets, DBPROP_COL_FIXEDLENGTH,
					VT_BOOL, (LPVOID)VARIANT_FALSE);
		odtLog	<< "\ttry to create a table with a variable length column of type " 
				<< rgColumnDesc[i].pwszTypeName << "\n";

		hr = CCNDropTable(NULL, cColumnDesc, rgColumnDesc, IID_IRowset, 0, NULL);

		if (S_OK != hr && !CHECK(hr, DB_S_ERRORSOCCURRED))
		{
			odtLog << "\t\tCould not create a table with DBPROP_COL_FIXEDLENGTH property value set to VARIANT_FALSE for this column.\n";
		}

		FreeProperties( &rgColumnDesc[i].cPropertySets, &rgColumnDesc[i].rgPropertySets);	
	}
	ReleaseColumnDesc(rgColumnDesc, cColumnDesc);
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(49)
//*-----------------------------------------------------------------------
// @mfunc Nullable/non nullable columns
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCCreateTable::Variation_49()
{ 
	BOOL					fTestRes = TEST_PASS;
	DBORDINAL				i;
	CCol					col;
	VARIANT					defval;
	HRESULT					hr;
	DBCOLUMNDESC			*rgColumnDesc	= NULL;
	DBORDINAL				cColumnDesc		= 0;
	CTable					*pTable			= new CTable(m_pThisTestModule->m_pIUnknown2, (LPWSTR)gwszModuleName);
	CList<WCHAR *,WCHAR *>	NativeTypesList;
	CList<DBTYPE,DBTYPE>	ProviderTypesList;
	HRESULT					hExpRes			= S_OK;
	BOOL					fSettable		= TRUE;
	BOOL					fSupported		= TRUE;
	DBPROP					*pPropDefault	= NULL;
	DBPROPSTATUS			ulStatus;
	ULONG					cPropSet, cProp;

	if (!SupportedProperty(DBPROP_COL_NULLABLE, DBPROPSET_COLUMN))
	{
		hExpRes		= DB_S_ERRORSOCCURRED;
		fSettable	= FALSE;
		fSupported	= FALSE;
	}
	else
		if (!SettableProperty(DBPROP_COL_NULLABLE, DBPROPSET_COLUMN))
			fSettable = FALSE;

	pTable->CreateTypeColInfo(NativeTypesList, ProviderTypesList);
	DuplicateColumnDesc(m_rgColumnDesc, m_cColumnDesc, &rgColumnDesc);
	cColumnDesc = m_cColumnDesc;
	ReleaseAllColumnPropSets(rgColumnDesc, cColumnDesc);
	//SetZeroColSize(rgColumnDesc, cColumnDesc);

	for (i=0; i<cColumnDesc; i++)
	{
		odtLog << "Type " << GetColumnTypeName(&rgColumnDesc[i]);
		// try to create a table in which column i is:
		// a) nullable
		// b) not nullable
		col = GetType(GetColumnTypeName(&rgColumnDesc[i]), rgColumnDesc[i].wType);
		switch (col.GetNullable())
		{
			case 0:
				odtLog << " (not nullable)\n";
				break;
			case 1:
				odtLog << " (NULLable)\n";
				break;
			default:
				odtLog << "\n";
		}

		// create a table with a nullable column
		SetProperty(&rgColumnDesc[i].rgPropertySets, &rgColumnDesc[i].cPropertySets, DBPROP_COL_NULLABLE,
					VT_BOOL, (LPVOID)VARIANT_TRUE, DBPROPOPTIONS_REQUIRED, DB_NULLID, DBPROPSET_COLUMN,
					&cPropSet, &cProp);
		
		odtLog << "\tcreate table with a nullable column: ";
		// create a table with a column property value set to VARIANT_TRUE for DBPROP_COL_NULLABLE
		hr = CCNDropTable(NULL, cColumnDesc, rgColumnDesc, IID_IRowset, 0, NULL);

		ulStatus = rgColumnDesc[i].rgPropertySets[cPropSet].rgProperties[cProp].dwStatus;
		if (	(S_OK == hr && !COMPARE(ulStatus, DBPROPSTATUS_OK))
			||	(!fSupported && !COMPARE(ulStatus, DBPROPSTATUS_NOTSUPPORTED))
			||	(S_OK != hr && fSettable && !COMPARE(ulStatus, DBPROPSTATUS_BADVALUE))
			||	(S_OK != hr && !fSettable && !COMPARE(ulStatus, DBPROPSTATUS_NOTSETTABLE))
			||	(!fSupported && !CHECK(hr, DB_E_ERRORSOCCURRED))
			||	(S_OK != hr && !CHECK(hr, DB_E_ERRORSOCCURRED)))
			fTestRes = TEST_FAIL;
		
		ReleaseAllColumnPropSets(&rgColumnDesc[i], 1);

		switch (col.GetNullable())
		{
			case 0:
				if (!CHECK(hr, DB_E_ERRORSOCCURRED))
					fTestRes = TEST_FAIL;
				break;
			case 1:
				if (!CHECK(hr, S_OK))
					fTestRes = TEST_FAIL;
				break;
			case -1:
				if (S_OK != hr && !CHECK(hr, DB_E_ERRORSOCCURRED))
					fTestRes = TEST_FAIL;
				break;
			default:
				ASSERT(FALSE);
				break;
		}

		odtLog << ((SUCCEEDED(hr)) ? "CREATED\n" : "INSUCCESS\n");

		// create a table with a column property value set to VARIANT_FALSE for DBPROP_COL_NULLABLE
		SetProperty(&rgColumnDesc[i].rgPropertySets, &rgColumnDesc[i].cPropertySets, DBPROP_COL_NULLABLE,
					VT_BOOL, (LPVOID)VARIANT_FALSE, DBPROPOPTIONS_REQUIRED, DB_NULLID, DBPROPSET_COLUMN,
					&cPropSet, &cProp);
		if (SettableProperty(DBPROP_COL_DEFAULT, DBPROPSET_COLUMN))
		{
			VariantInit(&defval);
			GetDefaultValue(&rgColumnDesc[i], &defval, pTable);
			if (SettableProperty(DBPROP_COL_DEFAULT, DBPROPSET_COLUMN))
				SetDefaultProperty(&rgColumnDesc[i].rgPropertySets, &rgColumnDesc[i].cPropertySets,
					&defval, DBPROPOPTIONS_REQUIRED);	// might be not supported
			VariantClear(&defval);
		}

		odtLog << "\tcreate table with a not nullable column\n";
		hr = CCNDropTable(NULL, cColumnDesc, rgColumnDesc, IID_IRowset, 0, NULL);
		
		ulStatus = rgColumnDesc[i].rgPropertySets[cPropSet].rgProperties[cProp].dwStatus;
		FindProperty(
			DBPROP_COL_DEFAULT,
			DBPROPSET_COLUMN,
			rgColumnDesc[i].cPropertySets,
			rgColumnDesc[i].rgPropertySets, 
			&pPropDefault
		);

		if (	(!pPropDefault || DBPROPSTATUS_OK == pPropDefault->dwStatus) 
			&&	(	(S_OK == hr && !COMPARE(ulStatus, DBPROPSTATUS_OK))
				||	(!fSupported && !COMPARE(ulStatus, DBPROPSTATUS_NOTSUPPORTED))
				||	(S_OK != hr && fSettable && !COMPARE(ulStatus, DBPROPSTATUS_BADVALUE))
				||	(S_OK != hr && !fSettable && !COMPARE(ulStatus, DBPROPSTATUS_NOTSETTABLE))
				||	(!fSupported && !CHECK(hr, DB_E_ERRORSOCCURRED))
				||	(S_OK != hr && !CHECK(hr, DB_E_ERRORSOCCURRED))))
			fTestRes = TEST_FAIL;

		if (FAILED(hr))
			odtLog << "Could not create a table with DBPROP_COL_NULLABLE property value set to VARIANT_FALSE.\n";

		ReleaseAllColumnPropSets(&rgColumnDesc[i], 1);
	}
	ReleaseColumnDesc(rgColumnDesc, cColumnDesc);
	delete pTable;
	return fTestRes;
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(50)
//*-----------------------------------------------------------------------
// @mfunc Primary key column
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCCreateTable::Variation_50()
{ 
	TBEGIN
	DBORDINAL		i;
	CCol			col;
	HRESULT			hr;
	DBCOLUMNDESC	*rgColumnDesc	= NULL;
	DBORDINAL		cColumnDesc		= 0;
	HRESULT			hExpRes			= S_OK;

	if (!SupportedProperty(DBPROP_COL_DEFAULT, DBPROPSET_COLUMN))
		hExpRes		= DB_S_ERRORSOCCURRED;

	DuplicateColumnDesc(m_rgColumnDesc, m_cColumnDesc, &rgColumnDesc);
	cColumnDesc = m_cColumnDesc;
	ReleaseAllColumnPropSets(rgColumnDesc, cColumnDesc);
	// this is to prevent SQL Server limiting the size of
	// the index it creates for primary key or unique columns
	SetZeroColSize(rgColumnDesc, cColumnDesc);

	for (i=0; i<cColumnDesc; i++)
	{
		odtLog << "Type " << GetColumnTypeName(&rgColumnDesc[i]) << "\n";
		// try to create a table in which column _rgColumnDesc[i].pwszTypeName is:
		// a) primary key
		// b) not primary key
		col = GetType(GetColumnTypeName(&rgColumnDesc[i]), rgColumnDesc[i].wType);

		// create a table with an primary key column
		SetProperty(&rgColumnDesc[i].rgPropertySets, &rgColumnDesc[i].cPropertySets, DBPROP_COL_PRIMARYKEY,
					VT_BOOL, (LPVOID)VARIANT_FALSE, DBPROPOPTIONS_OPTIONAL);

		if (S_OK != (hr = CCNDropTable(NULL, cColumnDesc, rgColumnDesc, IID_IRowset, 0, NULL)))
		{
			CHECK(hr, DB_S_ERRORSOCCURRED);
		}

		ReleaseAllColumnPropSets(&rgColumnDesc[i], 1);
		
		// create a table with a column property value set to VARIANT_FALSE for DBPROP_COL_PRIMARYKEY
		SetProperty(&rgColumnDesc[i].rgPropertySets, &rgColumnDesc[i].cPropertySets, DBPROP_COL_PRIMARYKEY,
					VT_BOOL, (LPVOID)VARIANT_TRUE, DBPROPOPTIONS_OPTIONAL);

		if (1 != col.GetNullable())
			hExpRes = DB_S_ERRORSOCCURRED;

		if (S_OK != (hr = CCNDropTable(NULL, cColumnDesc, rgColumnDesc, IID_IRowset, 0, NULL)))
		{
			CHECK(hr, DB_S_ERRORSOCCURRED);
		}

		ReleaseAllColumnPropSets(&rgColumnDesc[i], 1);
	}
	ReleaseColumnDesc(rgColumnDesc, cColumnDesc);

	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(51)
//*-----------------------------------------------------------------------
// @mfunc Unique columns
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCCreateTable::Variation_51()
{ 
	TBEGIN
	DBORDINAL		i;
	CCol			col;
	HRESULT			hr;
	DBCOLUMNDESC	*rgColumnDesc	= NULL;
	DBORDINAL		cColumnDesc		= 0;
	BOOL			fSupported		= FALSE;

	fSupported = SupportedProperty(DBPROP_COL_DEFAULT, DBPROPSET_COLUMN);

	DuplicateColumnDesc(m_rgColumnDesc, m_cColumnDesc, &rgColumnDesc);
	cColumnDesc = m_cColumnDesc;
	ReleaseAllColumnPropSets(rgColumnDesc, cColumnDesc);
	// this is to prevent SQL Server limiting the size of
	// the index it creates for primary key or unique columns
	SetZeroColSize(rgColumnDesc, cColumnDesc);

	for (i=0; i<cColumnDesc; i++)
	{
		odtLog << "Type " << GetColumnTypeName(&rgColumnDesc[i]) << "\n";
		// try to create a table in which column rgColumnDesc[i].pwszTypeName is:
		// a) unique
		// b) non-unique
		// there is no info whether a type can or cannot be unique
		col = GetType(GetColumnTypeName(&rgColumnDesc[i]), rgColumnDesc[i].wType);

		// create a table with an unique column
		SetProperty(&rgColumnDesc[i].rgPropertySets, &rgColumnDesc[i].cPropertySets, DBPROP_COL_UNIQUE,
					VT_BOOL, (LPVOID)VARIANT_TRUE, DBPROPOPTIONS_REQUIRED);
	
		hr = CCNDropTable(NULL, cColumnDesc, rgColumnDesc, IID_IRowset, 0, NULL);
		
		if (S_OK != hr)
		{
			odtLog << "Could not create a table with DBPROP_COL_UNIQUE property value set to VARIANT_TRUE for this column.\n";
			CHECK(hr, DB_E_ERRORSOCCURRED);
		}
		else
		{
			COMPARE(fSupported, TRUE);
		}
		ReleaseAllColumnPropSets(&rgColumnDesc[i], 1);

		// create a table with a column property value set to VARIANT_FALSE for DBPROP_COL_UNIQUE
		SetProperty(&rgColumnDesc[i].rgPropertySets, &rgColumnDesc[i].cPropertySets, DBPROP_COL_UNIQUE,
					VT_BOOL, (LPVOID)VARIANT_FALSE, DBPROPOPTIONS_OPTIONAL);

		hr = CCNDropTable(NULL, cColumnDesc, rgColumnDesc, IID_IRowset, 0, NULL);

		if (S_OK != hr)
		{
			odtLog << "Could not create a table with DBPROP_COL_UNIQUE property value set to VARIANT_FALSE for this column.\n";
			CHECK(hr, DB_S_ERRORSOCCURRED);
		}
		else
		{
			COMPARE(fSupported, TRUE);
		}

		ReleaseAllColumnPropSets(&rgColumnDesc[i], 1);
	}
	ReleaseColumnDesc(rgColumnDesc, cColumnDesc);
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(52)
//*-----------------------------------------------------------------------
// @mfunc Test conflicting properties
// a column that is both nullable and primary key
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCCreateTable::Variation_52()
{ 
	TBEGIN
	CCol			col;
	DBCOLUMNDESC	*rgColumnDesc	= NULL;
	DBORDINAL		cColumnDesc		= 0;
	
	TESTC_PROVIDER(SettableProperty(DBPROP_COL_NULLABLE, DBPROPSET_COLUMN)
		&&	SettableProperty(DBPROP_COL_PRIMARYKEY, DBPROPSET_COLUMN));

	DuplicateColumnDesc(m_rgColumnDesc, m_cColumnDesc, &rgColumnDesc);
	cColumnDesc = m_cColumnDesc;
	ReleaseAllColumnPropSets(rgColumnDesc, cColumnDesc);
	//SetZeroColSize(rgColumnDesc, cColumnDesc);

	// create a table with a column  showing contradiction in properties
	SetProperty(&rgColumnDesc[0].rgPropertySets, &rgColumnDesc[0].cPropertySets, DBPROP_COL_PRIMARYKEY,
					VT_BOOL, (LPVOID)VARIANT_TRUE, DBPROPOPTIONS_REQUIRED);
	SetProperty(&rgColumnDesc[0].rgPropertySets, &rgColumnDesc[0].cPropertySets, DBPROP_COL_NULLABLE,
					VT_BOOL, (LPVOID)VARIANT_TRUE, DBPROPOPTIONS_REQUIRED);

	TESTC_(CCNDropTable(NULL, cColumnDesc, rgColumnDesc, IID_IRowset, 0, NULL), DB_E_ERRORSOCCURRED);

CLEANUP:		
	ReleaseColumnDesc(rgColumnDesc, cColumnDesc);
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(53)
//*-----------------------------------------------------------------------
// @mfunc Create a table and ask for a rowset, setting DBPROP_ABORTPRESERVE
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCCreateTable::Variation_53()
{ 
	TBEGIN
	DBPROPSET		*rgPropertySets = NULL;
	ULONG			cPropertySets = 0;
	CCol			col;
	DBCOLUMNDESC	*rgColumnDesc	= NULL;
	DBORDINAL		cColumnDesc		= 0;

	DuplicateColumnDesc(m_rgColumnDesc, m_cColumnDesc, &rgColumnDesc);
	cColumnDesc = m_cColumnDesc;
	ReleaseAllColumnPropSets(rgColumnDesc, cColumnDesc);
	//SetZeroColSize(rgColumnDesc, cColumnDesc);

	TESTC_PROVIDER(SupportedProperty(DBPROP_ABORTPRESERVE, DBPROPSET_ROWSET)
		&&	SettableProperty(DBPROP_ABORTPRESERVE, DBPROPSET_ROWSET));
	SetProperty(&rgPropertySets, &cPropertySets, DBPROP_ABORTPRESERVE,
					VT_BOOL, (LPVOID)VARIANT_TRUE, DBPROPOPTIONS_REQUIRED, DB_NULLID, DBPROPSET_ROWSET);

	TESTC_(CCNDropTable(NULL, cColumnDesc, rgColumnDesc, IID_IRowsetInfo, 
		cPropertySets, rgPropertySets), S_OK);

CLEANUP:
	FreeProperties( &cPropertySets, &rgPropertySets);
	ReleaseColumnDesc(rgColumnDesc, cColumnDesc);
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(54)
//*-----------------------------------------------------------------------
// @mfunc Inserting rows after table creation, using the resulting rowset
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCCreateTable::Variation_54()
{ 
	IRowsetChange			*pIRowsetChange	= NULL;
	BOOL					fTestRes		= TEST_FAIL;
	BOOL					fMayWrite;
	DBORDINAL				i;
	const ULONG				nRows			= 10;
	DBID					*pTableID		= NULL;
	ULONG					cPropSets		= 0;
	DBPROPSET				*rgPropSets		= NULL;
	LONG					lUpdateInsert	= DBPROPVAL_UP_INSERT; 
	DBCOLUMNDESC			*rgColumnDesc	= NULL;
	DBORDINAL				cColumnDesc		= 0;
	CList <WCHAR*, WCHAR*>	ListNativeTemp;
	CList <DBTYPE, DBTYPE>	ListDataTypes;
	CTable					*pTable			= NULL;

	pTable = new CTable(m_pThisTestModule->m_pIUnknown2, (LPWSTR)gwszModuleName);
	// get the provider types list
	pTable->CreateColInfo(ListNativeTemp, ListDataTypes, ALLTYPES);
	// build the column description array
	pTable->BuildColumnDescs(&rgColumnDesc);
	cColumnDesc = pTable->CountColumnsOnTable();
	pTable->SetColumnDesc(rgColumnDesc, cColumnDesc);
	ReleaseAllColumnPropSets(rgColumnDesc, cColumnDesc);

	//Need to set DBPROP_UPDATABILITY: InsertRow is supported
	if (	!SupportedProperty(DBPROP_IRowsetChange, DBPROPSET_ROWSET)
		||	!SettableProperty(DBPROP_IRowsetChange, DBPROPSET_ROWSET))
	{
		fTestRes = TEST_SKIPPED;
		goto CLEANUP;
	}

	//Need to set DBPROP_UPDATABILITY: InsertRow is supported
	if (	!SupportedProperty(DBPROP_UPDATABILITY, DBPROPSET_ROWSET)
		||	!SettableProperty(DBPROP_UPDATABILITY, DBPROPSET_ROWSET))
	{
		fTestRes = TEST_SKIPPED;
		goto CLEANUP;
	}

	::SetProperty(	DBPROP_UPDATABILITY, DBPROPSET_ROWSET, &cPropSets, &rgPropSets, 
					DBTYPE_I4, (LPVOID)&lUpdateInsert);

	TESTC_(CreateAndCheckTable(m_pITableDefinition, NULL, NULL, cColumnDesc, rgColumnDesc, IID_IRowsetChange, 
		cPropSets, rgPropSets, &pTableID, (IUnknown**)&pIRowsetChange), S_OK);
	fTestRes = TEST_PASS;
	
	// find out if one can write to that table
	pTable->SetTableID(*pTableID);
	pTable->MayWrite(&fMayWrite);
	for (i=0; i<nRows; i++)
	{
		m_hr = Insert(0, pIRowsetChange, 0, NULL, pTable);
		if (DB_E_NOTSUPPORTED != m_hr)
		{
			if (!CHECK(m_hr, S_OK))
				fTestRes = TEST_FAIL;
		}
		else
			fTestRes = TEST_SKIPPED;
	}

CLEANUP:
	SAFE_RELEASE(pIRowsetChange);
	if (pTableID)
		CHECK(DropTableAndCheck(pTableID), S_OK);
	ReleaseDBID(pTableID);
	FreeProperties( &cPropSets, &rgPropSets);
	delete pTable;
	return fTestRes;
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(55)
//*-----------------------------------------------------------------------
// @mfunc Delete rows in the created rowset
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCCreateTable::Variation_55()
{ 
	IRowsetChange	*pIRowsetChange = NULL;
	IRowset			*pIRowset = NULL;
	BOOL			fTestRes = TEST_FAIL;
	ULONG			i, nSuccess;
	const ULONG		nRows = 10;
	const int		nProps = 3;
	DBPROPSET		rgPropSets[1];
	DBPROP			rgProperties[nProps];
	HROW			*rghRow = NULL; 
	DBCOUNTITEM		cRowsObtained = 0;
	DBROWSTATUS		rgRowStatus[nRows];
	DBID			*pTableID = NULL;
	BOOL			fMayWrite;
	DBCOLUMNDESC	*rgColumnDesc	= NULL;
	DBORDINAL		cColumnDesc		= 0;
	CList <WCHAR*, WCHAR*>	ListNativeTemp;
	CList <DBTYPE, DBTYPE>	ListDataTypes;
	CTable			*pTable = NULL;

	pTable = new CTable(m_pThisTestModule->m_pIUnknown2, (LPWSTR)gwszModuleName);
	// get the provider types list
	pTable->CreateColInfo(ListNativeTemp, ListDataTypes, ALLTYPES);
	// build the column description array
	pTable->BuildColumnDescs(&rgColumnDesc);
	ReleaseAllColumnPropSets(rgColumnDesc, cColumnDesc=pTable->CountColumnsOnTable());
	pTable->SetColumnDesc(rgColumnDesc, cColumnDesc);

	FILL_PROP_SET(rgPropSets[0], NUMELEM(rgProperties), rgProperties, DBPROPSET_ROWSET)
	FILL_PROP(rgProperties[0], DBPROP_IRowsetChange, VT_BOOL, V_BOOL, VARIANT_TRUE, DBPROPOPTIONS_OPTIONAL)
	FILL_PROP(rgProperties[1], DBPROP_OWNINSERT, VT_BOOL, V_BOOL, VARIANT_TRUE, DBPROPOPTIONS_REQUIRED)
	FILL_PROP(rgProperties[2], DBPROP_OWNUPDATEDELETE, VT_BOOL, V_BOOL, VARIANT_TRUE, DBPROPOPTIONS_OPTIONAL)

	TESTC_(CreateAndCheckTable(m_pITableDefinition, NULL, NULL, cColumnDesc, rgColumnDesc, IID_IRowsetChange, 
		NUMELEM(rgPropSets), rgPropSets, &pTableID, (IUnknown**)&pIRowsetChange), S_OK);	

	pTable->SetTableID(*pTableID);
	pTable->MayWrite(&fMayWrite);
	for (i=0; i<nRows; i++)
	{
		m_hr = Insert(0, pIRowsetChange, 0, NULL, pTable);
		if (DB_E_NOTSUPPORTED == m_hr)
		{
			odtLog << "IRowsetChange->Insert() is not supported\n";
			fTestRes = TEST_SKIPPED;
			goto CLEANUP;
		}
		else
			TESTC_(m_hr, S_OK);
	}

	// get a pointer to IRoewset interface
	if (!VerifyInterface(pIRowsetChange, IID_IRowset, ROWSET_INTERFACE, (IUnknown**)&pIRowset))
	{
		odtLog << "could not get IRowsetChange\n";
		goto CLEANUP;
	}

	m_hr = pIRowset->RestartPosition(NULL);
	if (!CHECK(m_hr = pIRowset->GetNextRows(
				0, 0,					// hChapter & lRowsOffset
				nRows,					// number of rows to be retrieved
				&cRowsObtained,		//number of rows actually get
				&rghRow				// array of handlers to rows
				), S_OK) || nRows != cRowsObtained)
	{
			odtLog << "insuccess on IRowset::GetNextRows\n";
			goto CLEANUP;
	}

	TESTC_(m_hr = pIRowsetChange->DeleteRows(0, cRowsObtained, rghRow, rgRowStatus), S_OK);

	for (i=nSuccess=0; i<nRows; i++)
		if (DBROWSTATUS_S_OK == rgRowStatus[i])
			nSuccess ++;

	if (nSuccess != nRows)
		odtLog << "delete succeeded for " << nRows-nSuccess << " rows out of " << nRows << "\n";
	else
		fTestRes = TEST_PASS;

CLEANUP:
	if (cRowsObtained)
		CHECK(m_hr = pIRowset->ReleaseRows(cRowsObtained, rghRow, NULL, NULL, NULL), S_OK);
	PROVIDER_FREE(rghRow);
	SAFE_RELEASE(pIRowsetChange);
	SAFE_RELEASE(pIRowset);
	if (pTableID)
	{
		CHECK(DropTableAndCheck(pTableID), S_OK);
		ReleaseDBID(pTableID);
	}
	delete pTable;
	return fTestRes;
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(56)
//*-----------------------------------------------------------------------
// @mfunc Aggregation, ask for IID_IUnknown
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCCreateTable::Variation_56()
{
	TBEGIN
	HRESULT				hr;
	DBID				*pTableID		= NULL;
	CAggregate			Aggregate(m_pIOpenRowset);
	DBCOLUMNDESC		*rgColumnDesc	= NULL;
	DBORDINAL			cColumnDesc		= 0;

	DuplicateColumnDesc(m_rgColumnDesc, m_cColumnDesc, &rgColumnDesc);
	cColumnDesc = m_cColumnDesc;
	ReleaseAllColumnPropSets(rgColumnDesc, cColumnDesc);

	TEST2C_(hr = CreateAndCheckTable(m_pITableDefinition, &Aggregate, NULL, cColumnDesc, rgColumnDesc, 
		IID_IUnknown, 0, NULL, &pTableID, (IUnknown**)&Aggregate.m_pIUnkInner), 
		S_OK, DB_E_NOAGGREGATION);

	TESTC_PROVIDER(S_OK == hr);
	// Verify Aggregation for this rowset...
	TESTC(Aggregate.VerifyAggregationQI(hr, IID_IRowset));

	
CLEANUP:
	Aggregate.ReleaseInner();
	// checkings, etc
	CHECK(DropTableAndCheck(pTableID), pTableID? S_OK: E_INVALIDARG);
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(57)
//*-----------------------------------------------------------------------
// @mfunc Create a table and ask for a rowset, setting DBPROP_COMMITPRESERVE
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCCreateTable::Variation_57()
{ 
	TBEGIN
	DBPROPID	rgPropID=DBPROP_COMMITPRESERVE;

	COMPARE(CreateWithOneRowsetProps(rgPropID, VT_BOOL, (LPVOID)VARIANT_TRUE, 
					(struct _GUID*)&IID_IRowsetInfo), TRUE);
	TESTC(CreateWithOneRowsetProps(rgPropID, VT_BOOL, (LPVOID)VARIANT_FALSE, 
					(struct _GUID*)&IID_IRowsetInfo));
	
CLEANUP:
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END


// {{ TCW_VAR_PROTOTYPE(58)
//*-----------------------------------------------------------------------
// @mfunc Create a table and ask for a rowset, setting DBPROP_OWNINSERT
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCCreateTable::Variation_58()
{ 
	TBEGIN
	DBPROPID	rgPropID=DBPROP_OWNINSERT;

	COMPARE(CreateWithOneRowsetProps(rgPropID, VT_BOOL, (LPVOID)VARIANT_TRUE, 
					(struct _GUID*)&IID_IRowsetInfo), TRUE);
	TESTC(CreateWithOneRowsetProps(rgPropID, VT_BOOL, (LPVOID)VARIANT_FALSE, 
					(struct _GUID*)&IID_IRowsetInfo));

CLEANUP:
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(59)
//*-----------------------------------------------------------------------
// @mfunc Create a table and ask for a rowset, setting DBPROP_BOOKMARKS
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCCreateTable::Variation_59()
{ 
	TBEGIN
	DBPROPID	rgPropID=DBPROP_BOOKMARKS;

	COMPARE(CreateWithOneRowsetProps(rgPropID, VT_BOOL, (LPVOID)VARIANT_TRUE, 
					(struct _GUID*)&IID_IRowsetInfo), TRUE);
	TESTC(CreateWithOneRowsetProps(rgPropID, VT_BOOL, (LPVOID)VARIANT_FALSE, 
					(struct _GUID*)&IID_IRowsetInfo));

CLEANUP:
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(60)
//*-----------------------------------------------------------------------
// @mfunc Create a table and ask for a rowset, setting DBPROP_CANHOLDROWS
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCCreateTable::Variation_60()
{ 
	TBEGIN
	DBPROPID	rgPropID=DBPROP_CANHOLDROWS;

	COMPARE(CreateWithOneRowsetProps(rgPropID, VT_BOOL, (LPVOID)VARIANT_TRUE, 
					(struct _GUID*)&IID_IRowsetInfo), TRUE);
	TESTC(CreateWithOneRowsetProps(rgPropID, VT_BOOL, (LPVOID)VARIANT_FALSE, 
					(struct _GUID*)&IID_IRowsetInfo));

CLEANUP:
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(61)
//*-----------------------------------------------------------------------
// @mfunc Create a table and ask for a rowset, setting DBPROP_MAYWRITECOLUMN
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCCreateTable::Variation_61()
{ 
	TBEGIN
	DBPROPID	rgPropID=DBPROP_MAYWRITECOLUMN;

	COMPARE(CreateWithOneRowsetProps(rgPropID, VT_BOOL, (LPVOID)VARIANT_TRUE, 
					(struct _GUID*)&IID_IRowsetInfo), TRUE);
	TESTC(CreateWithOneRowsetProps(rgPropID, VT_BOOL, (LPVOID)VARIANT_FALSE, 
					(struct _GUID*)&IID_IRowsetInfo));

CLEANUP:
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(62)
//*-----------------------------------------------------------------------
// @mfunc Ask for a rowset mandatory/optional interface when table creation => S_OK
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCCreateTable::Variation_62()
{ 
	BOOL					fTestRes = TEST_FAIL;
	IUnknown				*pIRowset = NULL;
	DBID					*pTableID = NULL;
	BOOL					fMayWrite;
	HRESULT					hr;
	DBCOLUMNDESC			*rgColumnDesc	= NULL;
	DBORDINAL				cColumnDesc		= 0;
	CList <WCHAR*, WCHAR*>	ListNativeTemp;
	CList <DBTYPE, DBTYPE>	ListDataTypes;
	CTable					*pTable = NULL;

	pTable = new CTable(m_pThisTestModule->m_pIUnknown2, (LPWSTR)gwszModuleName);
	// get the provider types list
	pTable->CreateColInfo(ListNativeTemp, ListDataTypes, ALLTYPES);
	// build the column description array
	pTable->BuildColumnDescs(&rgColumnDesc);
	ReleaseAllColumnPropSets(rgColumnDesc, cColumnDesc=pTable->CountColumnsOnTable());
	pTable->SetColumnDesc(rgColumnDesc, cColumnDesc);

	odtLog << "CreateTable and ask for a pointer to IRowset (mandatory)\n";
	CHECK(CCNDropTable(NULL, cColumnDesc, rgColumnDesc, IID_IRowset, 
					0, NULL), S_OK);

	odtLog << "CreateTable and ask for a pointer to IRowsetChange (optional)\n";
	CHECK(hr = CreateAndCheckTable(m_pITableDefinition, NULL, NULL, cColumnDesc, rgColumnDesc, 
		IID_IRowsetChange, 0, NULL, &pTableID, (IUnknown**)&pIRowset), S_OK);

	// try to use the IRowsetChange interface to insert a row
	if (SUCCEEDED(hr))
	{
		pTable->SetTableID(*pTableID);
		pTable->MayWrite(&fMayWrite);
		m_hr = Insert(0, (IRowsetChange*)pIRowset, 0, NULL, pTable);
		if (DB_E_NOTSUPPORTED != m_hr)
		{
			TESTC_(m_hr, S_OK);
		}
		else
		{
			fTestRes = TEST_SKIPPED;
			goto CLEANUP;
		}
	}

	fTestRes = TEST_PASS;

CLEANUP:
	// checkings, etc
	SAFE_RELEASE(pIRowset);
	if (pTableID)
	{
		CHECK(DropTableAndCheck(pTableID), S_OK);
		ReleaseDBID(pTableID);
	}
	delete pTable;
	return fTestRes;
} 
// }} TCW_VAR_PROTOTYPE_END


unsigned TCCreateTable::MyThreadProc(ULONG i)
{
	DBCOLUMNDESC	*rgColumnDesc	= NULL;
	DBID			TableID;
	DBID			*pTableID		= NULL;
	HRESULT			hr;

	if (i>= nThreads)
		return 0;
	DuplicateColumnDesc(m_rgColumnDesc, m_cColumnDesc, &rgColumnDesc);
	ReleaseAllColumnPropSets(rgColumnDesc, m_cColumnDesc);
	TableID.eKind			= DBKIND_NAME;
	TableID.uName.pwszName	= m_rgName[i];
	Sleep(0); // switch the context

	hr = m_pITableDefinition->CreateTable(NULL, m_rgName[i]? &TableID: NULL, 
			m_cColumnDesc, rgColumnDesc, IID_IRowset, 0, NULL, 
			m_rgName[i] ? NULL: &pTableID, NULL);
	Sleep(0); // switch the context

	m_rgResult[i] = hr;
	if (!m_rgName[i] && pTableID && DBKIND_NAME == pTableID->eKind)
	{
		m_rgName[i] = pTableID->uName.pwszName;
		SAFE_FREE(pTableID);
	}
	else
		ReleaseDBID(pTableID);
	ReleaseColumnDesc(rgColumnDesc, m_cColumnDesc);
	return 1;
} //TCCreateTable::MyThreadProc


// {{ TCW_VAR_PROTOTYPE(63)
//*-----------------------------------------------------------------------
// @mfunc threads on different tables
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCCreateTable::Variation_63()
{
	TBEGIN
	unsigned		rgIDThread[nThreads];
	HANDLE			hrgThread[nThreads];
	CInParam		rgThreadParam[nThreads];
	ULONG			i;
	WCHAR			number[3];
	LPWSTR			pwszBaseName = NULL;
	DBID			TableID;

	odtLog << "All table names are generated by user\n";
	m_pTable->MakeTableName(NULL);
	pwszBaseName = m_pTable->GetTableName();
	for (i=0; i< nThreads; i++)
	{
		rgThreadParam[i].pObject = this;
		rgThreadParam[i].i		= i;

		m_rgResult[i] = E_FAIL;
		
		m_rgName[i] = (WCHAR*)PROVIDER_ALLOC((3+wcslen(pwszBaseName))*sizeof(WCHAR));		
		ASSERT(m_rgName[i]);
		wcscpy(m_rgName[i], pwszBaseName);
		swprintf(number, L"%02d", i);
		wcscat(m_rgName[i], number);
	}
	
	for (i=0; i<nThreads; i++)
	{
		hrgThread[i] = (HANDLE)_beginthreadex(NULL, 0, ThreadProc,
							(void*)&rgThreadParam[i],
							0, 
							&rgIDThread[i]);		// input param
		TESTC(0 != hrgThread[i]);
	}

	WaitForMultipleObjects(nThreads, (CONST HANDLE*)hrgThread, TRUE, 1000);
	Sleep(1000);
	for (i=0; i< nThreads; i++)
		CloseHandle(hrgThread[i]);

	TableID.eKind = DBKIND_NAME;
	for (i=0; i<nThreads; i++)
	{
		if (CHECK(m_rgResult[i], S_OK))
		{
			TableID.uName.pwszName = m_rgName[i];
			CHECK(DropTableAndCheck(&TableID), S_OK);
		}
	}

	odtLog << "All table names are provider generated\n";
	for (i=0; i< nThreads; i++)
	{
		rgThreadParam[i].pObject = this;
		rgThreadParam[i].i		= i;

		m_rgResult[i] = E_FAIL;		
		m_rgName[i] = NULL;
	}
	
	for (i=0; i<nThreads; i++)
	{
		hrgThread[i] = (HANDLE)_beginthreadex(NULL, 0, ThreadProc,
							(void*)&rgThreadParam[i],
							0, 
							&rgIDThread[i]);		// input param
		TESTC(0 != hrgThread[i]);
	}

	WaitForMultipleObjects(nThreads, (CONST HANDLE*)hrgThread, TRUE, 1000);
	Sleep(1000);
	for (i=0; i< nThreads; i++)
		CloseHandle(hrgThread[i]);

	for (i=0; i<nThreads; i++)
		CHECK(m_rgResult[i], S_OK);

CLEANUP:
	TableID.eKind = DBKIND_NAME;
	for (i=0; i<nThreads; i++)
	{
		TableID.uName.pwszName = m_rgName[i];
		if (SUCCEEDED(m_rgResult[i]))
			CHECK(DropTableAndCheck(&TableID), S_OK);
		PROVIDER_FREE(m_rgName[i]);
	}

	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(64)
//*-----------------------------------------------------------------------
// @mfunc threads on the same table
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCCreateTable::Variation_64()
{ 
	unsigned		rgIDThread[nThreads];
	HANDLE			hrgThread[nThreads];
	CInParam		rgThreadParam[nThreads];
	BOOL			fTestResult = TEST_FAIL;
	ULONG			i, nS_OK, nDB_E_DUPLICATETABLEID;
	LPWSTR			pwszBaseName = NULL;
	DBID			TableID;

	m_pTable->MakeTableName(NULL);
	pwszBaseName = m_pTable->GetTableName();
	for (i=0; i< nThreads; i++)
	{
		m_rgResult[i]				= E_FAIL;
		m_rgName[i]					= pwszBaseName;
		rgThreadParam[i].pObject	= this;
		rgThreadParam[i].i			= i;
	}
	
	// creates a table, build rgColumnDesc by it
	for (i=0; i<nThreads; i++)
	{
		hrgThread[i] = (HANDLE)_beginthreadex(NULL, 0, ThreadProc,
							(void*)&rgThreadParam[i],
							0, 
							&rgIDThread[i]);		// input param
		TESTC(0 != hrgThread[i]);
	}

	WaitForMultipleObjects(nThreads, (CONST HANDLE*)hrgThread, TRUE, 1000);
	Sleep(1000);
	for (i=0; i< nThreads; i++)
		CloseHandle(hrgThread[i]);

	for (i=nS_OK=nDB_E_DUPLICATETABLEID=0; i<nThreads; i++)
	{
		if (m_rgResult[i] == S_OK)
			nS_OK++;
		else if (CHECK(m_rgResult[i], DB_E_DUPLICATETABLEID))
			nDB_E_DUPLICATETABLEID++;
		else
		{
			odtLog << "Thread " << i << ": unexpected result " << m_rgResult[i] << "\n";
			goto CLEANUP;
		}
	}

	TESTC(nS_OK == 1 && nDB_E_DUPLICATETABLEID == nThreads-1);
	fTestResult = TEST_PASS;

CLEANUP:
	TableID.eKind = DBKIND_NAME;
	TableID.uName.pwszName = pwszBaseName;
	CHECK(DropTableAndCheck(&TableID), S_OK);
	return fTestResult;
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(65)
//*-----------------------------------------------------------------------
// @mfunc try all interfaces on rowset that can be returned
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCCreateTable::Variation_65()
{ 
	TBEGIN
	const ULONG				nInterfaces = 19;			// number of total interfaces
	const ULONG				nMandatoryInterfaces = 6;	// the number of mandatory interfaces
	const IID*				rgRIIDInterfaces[nInterfaces] = {&IID_IUnknown, &IID_IAccessor, &IID_IColumnsInfo, 
								&IID_IConvertType, &IID_IRowset, &IID_IRowsetInfo, &IID_IChapteredRowset, 
								&IID_IColumnsRowset, &IID_IConnectionPointContainer, &IID_IDBAsynchStatus, 
								&IID_IRowsetChange, &IID_IRowsetFind, &IID_IRowsetIdentity, &IID_IRowsetLocate, 
								&IID_IRowsetResynch, &IID_IRowsetScroll, &IID_IRowsetUpdate, &IID_IRowsetView, 
								&IID_ISupportErrorInfo};
	LPWSTR					rgInterfaceNames[nInterfaces] = {L"IUnknown", L"IAccessor", L"IColumnsInfo", 
								L"IConvertType", L"IRowset", L"IRowsetInfo", L"IChapteredRowset", 
								L"IColumnsRowset", L"IConnectionPointContainer", L"IDBAsynchStatus", 
								L"IRowsetChange", L"IRowsetFind", L"IRowsetIdentity", L"IRowsetLocate", 
								L"IRowsetResynch", L"IRowsetScroll", L"IRowsetUpdate", L"IRowsetView", 
								L"ISupportErrorInfo"};
	const DBPROPID			rgInterfaceID[nInterfaces-1] = {DBPROP_IAccessor, DBPROP_IColumnsInfo, 
								DBPROP_IConvertType, DBPROP_IRowset, DBPROP_IRowsetInfo, DBPROP_IChapteredRowset, 
								DBPROP_IColumnsRowset, DBPROP_IConnectionPointContainer, DBPROP_IDBAsynchStatus, 
								DBPROP_IRowsetChange, DBPROP_IRowsetFind, DBPROP_IRowsetIdentity, DBPROP_IRowsetLocate, 
								DBPROP_IRowsetResynch, DBPROP_IRowsetScroll, DBPROP_IRowsetUpdate, DBPROP_IRowsetView, 
								DBPROP_ISupportErrorInfo};
//	BOOL					fTestRes = TEST_PASS;
	ULONG					i, j;
	IUnknown				*pRowset = NULL;			
	IUnknown				*pIUnknown = NULL;
	DBPROPSET				rgPropertySets[2];
	DBPROP					rgProperties[nInterfaces-1];
	DBPROP					rgProp2[1];
	DBID					*pTableID = NULL;
	HRESULT					hr;
	HRESULT					hRes = S_OK;
	HRESULT					hExpectedRes = S_OK;
	DBCOLUMNDESC			*rgColumnDesc	= NULL;
	DBORDINAL				cColumnDesc		= 0;
	BOOL					fRetrieve		= true;
	BOOL					fPropSupported;

	FILL_PROP_SET(rgPropertySets[0], NUMELEM(rgProperties), rgProperties, DBPROPSET_ROWSET);
	for (i=0; i<nInterfaces-1; i++)
	{
		FILL_PROP(rgProperties[i], rgInterfaceID[i], VT_BOOL, V_BOOL, VARIANT_TRUE, DBPROPOPTIONS_OPTIONAL);
		if (!SupportedProperty(rgInterfaceID[i], DBPROPSET_ROWSET))
			hRes = DB_S_ERRORSOCCURRED;
	}
	FILL_PROP_SET(rgPropertySets[1], NUMELEM(rgProp2), rgProp2, DBPROPSET_ROWSET);
	FILL_PROP(rgProp2[0], DBPROP_ISequentialStream, VT_BOOL, V_BOOL, VARIANT_TRUE, DBPROPOPTIONS_OPTIONAL);
	if (!SupportedProperty(DBPROP_ISequentialStream, DBPROPSET_ROWSET))
		hRes = DB_S_ERRORSOCCURRED;

	DuplicateColumnDesc(m_rgColumnDesc, m_cColumnDesc, &rgColumnDesc);
	cColumnDesc = m_cColumnDesc;
	ReleaseAllColumnPropSets(rgColumnDesc, cColumnDesc);
	
	for (i=0; i<nInterfaces; i++)
	{
		odtLog << "\t" << rgInterfaceNames[i] << ((i<nMandatoryInterfaces)? "(mandatory)\n" : "\n");
		PRVTRACE(L"TCCreateTable::Variation_65(): iteration %d (%s)\n", 
			i, ((i>0) ? rgInterfaceNames[i] : L"IUnknown"));
		fPropSupported = (i>0)? SupportedProperty(rgInterfaceID[i-1], DBPROPSET_ROWSET): TRUE;
		hExpectedRes = ((i>0) && !fPropSupported)? E_NOINTERFACE: hRes;

		// This interface is only supported if user sets DBPROP_ROWSET_ASYNCH in the 
		// rowset properties otherwise its unsupported.
		if (i>0 && rgInterfaceID[i-1] == DBPROP_IDBAsynchStatus)
		{
			fPropSupported = FALSE;
			hExpectedRes = E_NOINTERFACE;
		}

		// if the interface is mandatory, it has to be supported
		// note that there is not a DBPROP_IUnknown, so the condition is i>nMandatoryInterfaces
		COMPARE(i==0 || fPropSupported || i>=nMandatoryInterfaces, TRUE);

		CHECK(CCNDropTable(NULL, cColumnDesc, rgColumnDesc,
			*rgRIIDInterfaces[i], 0, NULL, 
			FALSE), fPropSupported? S_OK: E_NOINTERFACE);

		pRowset = NULL;
		CHECK(hr = CreateAndCheckTable(m_pITableDefinition, NULL, NULL, cColumnDesc, rgColumnDesc,
			*rgRIIDInterfaces[i], NUMELEM(rgPropertySets), rgPropertySets, 
			&pTableID, &pRowset), hExpectedRes);

		if (S_OK != hr && DB_S_ERRORSOCCURRED != hr)
		{
			if (i<nMandatoryInterfaces)
			{
				odtLog << "could not get the mandatory interface " << rgInterfaceNames[i] << "\n";
				COMPARE(TRUE, FALSE);			
			}
		}
		else
		{
			// try to get all the other interfaces
			if (pRowset)
			{
				fRetrieve = CHECK(pRowset->QueryInterface(IID_IUnknown, 
						(void**)&pIUnknown), S_OK) ? fRetrieve: FALSE;
				SAFE_RELEASE(pIUnknown);
				
				// all the other interfaces considered
				for (j=1; j<nInterfaces; j++)
				{
					odtLog << "\tTesting: " << rgInterfaceNames[j] << "\n";

					if (	(j<nMandatoryInterfaces) 
						&&	(	!COMPARE(rgProperties[j-1].dwStatus, DBPROPSTATUS_OK)
							||	!CHECK(pRowset->QueryInterface(*rgRIIDInterfaces[j], (void**)&pIUnknown), S_OK)))
					{
						odtLog << "Could not retrieve mandatory interface " << rgInterfaceNames[j] << "\n";
						continue;
					}
					SAFE_RELEASE(pIUnknown);
					fRetrieve = TRUE;
					// the interface should be retrievable if and only if the propstatus is ok 
					if (DBPROPSTATUS_OK == rgProperties[j-1].dwStatus)
					{
						fRetrieve = CHECK(pRowset->QueryInterface(*rgRIIDInterfaces[j], 
							(void**)&pIUnknown), S_OK) ? fRetrieve: FALSE;
						SAFE_RELEASE(pIUnknown);
					}
					else
					{
						fRetrieve = CHECK(pRowset->QueryInterface(*rgRIIDInterfaces[j], 
							(void**)&pIUnknown), E_NOINTERFACE) ? fRetrieve: FALSE;
					}
					// check on prop status
					if (SupportedProperty(rgInterfaceID[j-1], DBPROPSET_ROWSET))
					{
						if (SettableProperty(rgInterfaceID[j-1], DBPROPSET_ROWSET))
							fRetrieve = ((DBPROPSTATUS_NOTSET != rgProperties[j-1].dwStatus  
									&& !COMPARE(rgProperties[j-1].dwStatus, DBPROPSTATUS_OK))) ? FALSE: fRetrieve;
						else
							fRetrieve = (DBPROPSTATUS_OK != rgProperties[j-1].dwStatus
									&& !COMPARE(rgProperties[j-1].dwStatus, DBPROPSTATUS_NOTSETTABLE)) ? FALSE: fRetrieve;
					}
					else
					{
						fRetrieve = (!COMPARE(rgProperties[j-1].dwStatus, DBPROPSTATUS_NOTSUPPORTED))? FALSE: fRetrieve;
					}
					if (!fRetrieve)
					{
						odtLog << "ERROR: retrieving interface " << rgInterfaceNames[j] << "\n";
					}
				}
			}
		}
		if (pRowset)
			SAFE_RELEASE(pRowset);
		if (pTableID)
			CHECK(DropTableAndCheck(pTableID), S_OK);
		ReleaseDBID(pTableID);
	}

	ReleaseColumnDesc(rgColumnDesc, cColumnDesc);
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(66)
//*-----------------------------------------------------------------------
// @mfunc create with a table property => S_OK
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCCreateTable::Variation_66()
// just try the creation of a table with the specified property
// there is not any method to retrieve the property of the table
{ 
	TBEGIN
	DBPROPSET		rgPropSets[1];
	DBPROP			rgProp[1];
	HRESULT			hr;
	DBCOLUMNDESC	*rgColumnDesc	= NULL;
	DBORDINAL		cColumnDesc		= 0;
	DBID			TableID;
	BOOL			fSupported;
	BOOL			fSettable;
	BOOL			fValidate;

	DuplicateColumnDesc(m_rgColumnDesc, m_cColumnDesc, &rgColumnDesc);
	cColumnDesc = m_cColumnDesc;
	ReleaseAllColumnPropSets(rgColumnDesc, cColumnDesc);

	TableID.eKind			= DBKIND_NAME;
	TableID.uName.pwszName	= NULL;

	fSupported	= SupportedProperty(DBPROP_TBL_TEMPTABLE, DBPROPSET_TABLE);
	fSettable	= SettableProperty(DBPROP_TBL_TEMPTABLE, DBPROPSET_TABLE);
	fValidate	= fSettable || !fSupported;

	hr = fSettable? S_OK : DB_E_ERRORSOCCURRED;

	odtLog << "Property is REQUIRED\n";
	// temp table, TableID generated by provider
	odtLog << "\tProvider generated TableID\n";
	FILL_PROP_SET(rgPropSets[0], NUMELEM(rgProp), rgProp, DBPROPSET_TABLE);
	FILL_PROP(rgProp[0], DBPROP_TBL_TEMPTABLE, VT_BOOL, V_BOOL, VARIANT_TRUE, DBPROPOPTIONS_REQUIRED);

	hr = CCNDropTable(NULL, cColumnDesc, rgColumnDesc, IID_IRowset, NUMELEM(rgPropSets), rgPropSets);
	if (fValidate && fSettable || S_OK == hr)
	{
		CHECK(hr, S_OK);
		COMPARE(rgProp[0].dwStatus, DBPROPSTATUS_OK);
	}
	else
	{
		CHECK(hr, DB_E_ERRORSOCCURRED);
		if (fSupported)
		{	COMPARE(DBPROPSTATUS_NOTSETTABLE == rgProp[0].dwStatus, TRUE);}
		else
		{	COMPARE(DBPROPSTATUS_NOTSUPPORTED == rgProp[0].dwStatus, TRUE);}
	}

	// perm table, TableID generated by provider
	FILL_PROP(rgProp[0], DBPROP_TBL_TEMPTABLE, VT_BOOL, V_BOOL, VARIANT_FALSE, DBPROPOPTIONS_REQUIRED);
	hr = (S_OK!=hr)? DB_E_ERRORSOCCURRED : S_OK;
	CHECK(CCNDropTable(NULL, cColumnDesc, rgColumnDesc, IID_IRowset, 
					NUMELEM(rgPropSets), rgPropSets), hr);

	// temp table, consumer generated TableID 
	odtLog << "\tConsumer generated TableID\n";
	m_pTable->MakeTableName(NULL);
	TableID.eKind = DBKIND_NAME;
	TableID.uName.pwszName = wcsDuplicate(m_pTable->GetTableName());
	FILL_PROP_SET(rgPropSets[0], NUMELEM(rgProp), rgProp, DBPROPSET_TABLE);
	FILL_PROP(rgProp[0], DBPROP_TBL_TEMPTABLE, VT_BOOL, V_BOOL, VARIANT_TRUE, DBPROPOPTIONS_REQUIRED);
	hr = CCNDropTable(&TableID, cColumnDesc, rgColumnDesc, IID_IRowset, NUMELEM(rgPropSets), rgPropSets);

	// perm table, consumer generated TableID 
	FILL_PROP(rgProp[0], DBPROP_TBL_TEMPTABLE, VT_BOOL, V_BOOL, VARIANT_FALSE, DBPROPOPTIONS_REQUIRED);
	hr = (S_OK!=hr)? DB_E_ERRORSOCCURRED : S_OK;
	CHECK(CCNDropTable(&TableID, cColumnDesc, rgColumnDesc, IID_IRowset, 
					NUMELEM(rgPropSets), rgPropSets), hr);
	
	hr = fSettable? S_OK : DB_S_ERRORSOCCURRED;

	odtLog << "Property is OPTIONAL\n";
	// temp table, TableID generated by provider
	odtLog << "\tProvider generated TableID\n";
	FILL_PROP_SET(rgPropSets[0], NUMELEM(rgProp), rgProp, DBPROPSET_TABLE);
	FILL_PROP(rgProp[0], DBPROP_TBL_TEMPTABLE, VT_BOOL, V_BOOL, VARIANT_TRUE, DBPROPOPTIONS_OPTIONAL);
	TEST2C_(hr = CCNDropTable(NULL, cColumnDesc, rgColumnDesc, IID_IRowset, 
					NUMELEM(rgPropSets), rgPropSets), S_OK, DB_S_ERRORSOCCURRED);

	// perm table, TableID generated by provider
	FILL_PROP(rgProp[0], DBPROP_TBL_TEMPTABLE, VT_BOOL, V_BOOL, VARIANT_FALSE, DBPROPOPTIONS_OPTIONAL);
	hr = (S_OK!=hr)? DB_S_ERRORSOCCURRED : S_OK;
	CHECK(CCNDropTable(NULL, cColumnDesc, rgColumnDesc, IID_IRowset, 
					NUMELEM(rgPropSets), rgPropSets), hr);

	// temp table, consumer generated TableID 
	odtLog << "\tConsumer generated TableID\n";
	m_pTable->MakeTableName(NULL);
	TableID.eKind = DBKIND_NAME;
	TableID.uName.pwszName = wcsDuplicate(m_pTable->GetTableName());
	FILL_PROP_SET(rgPropSets[0], NUMELEM(rgProp), rgProp, DBPROPSET_TABLE);
	FILL_PROP(rgProp[0], DBPROP_TBL_TEMPTABLE, VT_BOOL, V_BOOL, VARIANT_TRUE, DBPROPOPTIONS_OPTIONAL);
	TEST2C_(hr = CCNDropTable(&TableID, cColumnDesc, rgColumnDesc, IID_IRowset, 
					NUMELEM(rgPropSets), rgPropSets), S_OK, DB_S_ERRORSOCCURRED);

	// perm table, consumer generated TableID 
	FILL_PROP(rgProp[0], DBPROP_TBL_TEMPTABLE, VT_BOOL, V_BOOL, VARIANT_FALSE, DBPROPOPTIONS_OPTIONAL);
	hr = (S_OK!=hr)? DB_S_ERRORSOCCURRED : S_OK;
	TESTC_(CCNDropTable(&TableID, cColumnDesc, rgColumnDesc, IID_IRowset, 
					NUMELEM(rgPropSets), rgPropSets), hr);

CLEANUP:
	// checkings, etc
	ReleaseColumnDesc(rgColumnDesc, cColumnDesc);
	ReleaseDBID(&TableID, FALSE);
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(67)
//*-----------------------------------------------------------------------
// @mfunc create a table and update a row, using the rowset interface got => S_OK
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCCreateTable::Variation_67()
{ 
	IRowsetChange	*pIRowsetChange	= NULL;
	IRowset			*pIRowset		= NULL;
	IAccessor		*pIAccessor		= NULL;
	BOOL			fTestRes		= TEST_FAIL;
	ULONG			i;
	const ULONG		nInsertRows		= 10;
	BOOL			fMayWrite;
	const ULONG		nRows			= 3;
	DBPROPSET		rgPropSets[1];
	const ULONG		nProps			= 3;
	DBPROP			rgProperties[nProps];
	HROW			*rghRow			= NULL;
	DBCOUNTITEM		cRowsObtained	= 0;
	HACCESSOR		hAccessor		= NULL;
	BYTE			*pData			= NULL;
	DBCOUNTITEM		cBindings		= 0;
	DBBINDING		*rgBindings		= NULL;
	const LONG		cColsToBind		= 1;
	LONG_PTR		rgColsToBind[cColsToBind];
	DBID			*pTableID		= NULL;
	DBCOLUMNDESC	*rgColumnDesc	= NULL;
	DBORDINAL		cColumnDesc		= 0;
	CList <WCHAR*, WCHAR*>	ListNativeTemp;
	CList <DBTYPE, DBTYPE>	ListDataTypes;
	CTable			*pTable = NULL;

	pTable = new CTable(m_pThisTestModule->m_pIUnknown2, (LPWSTR)gwszModuleName);
	// get the provider types list
	pTable->CreateColInfo(ListNativeTemp, ListDataTypes, ALLTYPES);
	// build the column description array
	pTable->BuildColumnDescs(&rgColumnDesc);
	ReleaseAllColumnPropSets(rgColumnDesc, cColumnDesc=pTable->CountColumnsOnTable());
	pTable->SetColumnDesc(rgColumnDesc, cColumnDesc);

	FILL_PROP_SET(rgPropSets[0], NUMELEM(rgProperties), rgProperties, DBPROPSET_ROWSET);
	FILL_PROP(rgProperties[0], DBPROP_IRowsetChange, VT_BOOL, V_BOOL, VARIANT_TRUE, DBPROPOPTIONS_REQUIRED);
	FILL_PROP(rgProperties[1], DBPROP_OWNINSERT, VT_BOOL, V_BOOL, VARIANT_TRUE, DBPROPOPTIONS_REQUIRED);
	FILL_PROP(rgProperties[2], DBPROP_OWNUPDATEDELETE, VT_BOOL, V_BOOL, VARIANT_TRUE, DBPROPOPTIONS_OPTIONAL);

	TESTC_(CreateAndCheckTable(m_pITableDefinition, NULL, NULL, cColumnDesc, rgColumnDesc, IID_IRowsetChange, 1, rgPropSets,
		&pTableID, (IUnknown**)&pIRowsetChange), S_OK);

	pTable->SetTableID(*pTableID);
	pTable->MayWrite(&fMayWrite);
	for (i=0; i<nInsertRows; i++)
	{
		m_hr = Insert(0, pIRowsetChange, 0, NULL, pTable);
		if (DB_E_NOTSUPPORTED != m_hr)
		{
			TESTC_(m_hr, S_OK);
		}
		else
		{
			fTestRes = TEST_SKIPPED;
			goto CLEANUP;
		}

	}

	// get a pointer to IRoewset interface
	if (!VerifyInterface(pIRowsetChange, IID_IRowset, ROWSET_INTERFACE, (IUnknown**)&pIRowset))
	{
		odtLog << "could not get IRowsetChange\n";
		goto CLEANUP;
	}

	if (!VerifyInterface(pIRowset, IID_IAccessor, ROWSET_INTERFACE, (IUnknown**)&pIAccessor))
	{
		odtLog << "could not get IAccessor\n";
		goto CLEANUP;
	}

	m_hr = pIRowset->RestartPosition(NULL);

	if (!CHECK(m_hr = pIRowset->GetNextRows(0, 0,					// hChapter & lRowsOffset
											nRows,					// number of rows to be retrieved
											&cRowsObtained,		//number of rows actually get
											&rghRow				// array of handlers to rows
											), S_OK) || nRows != cRowsObtained)
	{
		odtLog << "insuccess on IRowset::GetNextRows\n";
		goto CLEANUP;
	}

	rgColsToBind[0] = 1;
	if (!CHECK(m_hr = GetAccessorAndBindings(pIRowset,	// pIUnknRowsetObject
					DBACCESSOR_ROWDATA,							// accessor flags
					&hAccessor, &rgBindings, &cBindings, NULL,	// accessor handler, array and number of bindings created
					DBPART_VALUE |DBPART_STATUS |DBPART_LENGTH,	// types of bindings to do
					USE_COLS_TO_BIND_ARRAY,						// eColsByRef specifies that cols to be bind 
																//are gien as an array
					FORWARD,									// eBindingOrder
					NO_COLS_BY_REF,								// eColsByRef
					NULL, NULL,
					NULL, DBTYPE_EMPTY, 						// ppStringsBufferOut & dwModifier
					cColsToBind, rgColsToBind), S_OK))
	{
		odtLog << "problems getting accessor and bindings\n";
		goto CLEANUP;
	}

	// Fill buffer with appropriate data for insert of this row number
	TESTC_(m_hr = FillInputBindings(
		pTable,
		DBACCESSOR_ROWDATA,		
		cBindings,
		rgBindings,	
		&pData,		
		37,						
		0,
		NULL),S_OK);

	if (!CHECK(m_hr = pIRowsetChange->SetData(rghRow[0], hAccessor, pData), S_OK))
	{
		odtLog << "could not update the row\n";
		goto CLEANUP;
	}
	fTestRes = TEST_PASS;

CLEANUP:
	if (pIAccessor && hAccessor)
	{
		CHECK(m_hr = pIAccessor->ReleaseAccessor(hAccessor, NULL), S_OK);
	}
	SAFE_RELEASE(pIAccessor);
	if (pIRowset)
		CHECK(m_hr = pIRowset->ReleaseRows(cRowsObtained, rghRow, NULL, NULL, NULL), S_OK);
	PROVIDER_FREE(rghRow);
	SAFE_RELEASE(pIRowsetChange);
	SAFE_RELEASE(pIRowset);
	if (pTableID)
	{
		CHECK(DropTableAndCheck(pTableID), S_OK);
		ReleaseDBID(pTableID);
	}
	delete pTable;
	FreeAccessorBindings(cBindings, rgBindings);
	PROVIDER_FREE(pData);
	return fTestRes;
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(68)
//*-----------------------------------------------------------------------
// @mfunc Fully Qualified Table Name
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCCreateTable::Variation_68()
{ 
	BOOL			fTestRes = TEST_FAIL;
	DBID			TableID;
	WCHAR			*pwszQualTableName = NULL;
	WCHAR			*pwszCatalogName = NULL;
	WCHAR			*pwszSchemaName = NULL;
	WCHAR			*pwszTableName = NULL;
	DBCOLUMNDESC	*rgColumnDesc	= NULL;
	DBORDINAL		cColumnDesc		= 0;
	CTable			*pTable = NULL;

	// create a regular table
	pTable = new CTable(m_pThisTestModule->m_pIUnknown2, (LPWSTR)gwszModuleName);
	TESTC(NULL != pTable);
	TESTC_(pTable->CreateTable(0, 0), S_OK);
	pwszTableName = pTable->GetTableName();
	TableID.eKind = DBKIND_NAME;

	TESTC(GetCatalogSchemaNames(pwszTableName, &pwszCatalogName, &pwszSchemaName, pTable));

	//Construct a fully Qualified TableName...
	TESTC_(pTable->GetQualifiedName(pwszCatalogName, pwszSchemaName, pwszTableName, &pwszQualTableName),S_OK);
	TableID.uName.pwszName = pwszQualTableName;

	// get rid of the previous table; keep info about "the empty shell"
	m_pITableDefinition->DropTable(&pTable->GetTableID());

	// create the table with the qualified name
	pTable->BuildColumnDescs(&rgColumnDesc);
	pTable->SetColumnDesc(rgColumnDesc, cColumnDesc=pTable->CountColumnsOnTable());

	TESTC_(CCNDropTable(&TableID, cColumnDesc, rgColumnDesc, IID_IRowset, 0, NULL), S_OK);
	fTestRes = TEST_PASS;
    
CLEANUP:
	SAFE_FREE(pwszCatalogName);
	SAFE_FREE(pwszSchemaName);
	SAFE_FREE(pwszQualTableName);
	pTable->DropTable();
	delete pTable;
    return fTestRes;
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(69)
//*-----------------------------------------------------------------------
// @mfunc Quoted table name
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCCreateTable::Variation_69()
{ 
	TBEGIN
	DBID			TableID;
	DBCOLUMNDESC	*rgColumnDesc	= NULL;
	DBORDINAL		cColumnDesc		= 0;

	TableID.eKind = DBKIND_NAME;
	TableID.uName.pwszName = NULL;
	DuplicateColumnDesc(m_rgColumnDesc, m_cColumnDesc, &rgColumnDesc);
	cColumnDesc = m_cColumnDesc;
	ReleaseAllColumnPropSets(rgColumnDesc, cColumnDesc);
	m_pTable->MakeTableName(NULL);
	m_pTable->GetQuotedName(m_pTable->GetTableName(), &TableID.uName.pwszName);
	TESTC_(CCNDropTable(&TableID, cColumnDesc, rgColumnDesc, IID_IRowset, 0, NULL), S_OK);

CLEANUP:
	ReleaseDBID(&TableID, FALSE);
	ReleaseColumnDesc(rgColumnDesc, cColumnDesc);
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(70)
//*-----------------------------------------------------------------------
// @mfunc Aggregation, non IID_IUnknown
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCCreateTable::Variation_70()
{ 
	TBEGIN
	DBID				*pTableID		= NULL;
	CAggregate			Aggregate(m_pIOpenRowset);
	DBCOLUMNDESC		*rgColumnDesc	= NULL;
	DBORDINAL			cColumnDesc		= 0;

	DuplicateColumnDesc(m_rgColumnDesc, m_cColumnDesc, &rgColumnDesc);
	cColumnDesc = m_cColumnDesc;
	ReleaseAllColumnPropSets(rgColumnDesc, cColumnDesc);

	TESTC_(CreateAndCheckTable(m_pITableDefinition, &Aggregate, NULL, cColumnDesc, rgColumnDesc, 
		IID_IRowsetChange, 0, NULL, &pTableID, (IUnknown**)&Aggregate.m_pIUnkInner), 
		DB_E_NOAGGREGATION);

	// Verrify Aggregation for this rowset...
	TESTC(NULL == Aggregate.m_pIUnkInner);

CLEANUP:	
	ReleaseColumnDesc(rgColumnDesc, cColumnDesc);
	Aggregate.ReleaseInner();
	// checkings, etc
	DropTableAndCheck(pTableID);
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(71)
//*-----------------------------------------------------------------------
// @mfunc Aggregation -> IRowsetInfo::GetReferencedRowset
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCCreateTable::Variation_71()
{ 
	TBEGIN
	HRESULT				hr;
	DBID				*pTableID		= NULL;
	CAggregate			Aggregate(m_pIOpenRowset);
    IRowsetInfo			*pIRowsetInfo	= NULL;
	IUnknown			*pIAggregate	= NULL;
	IUnknown			*pIUnkOuter		= NULL;
	DBCOLUMNDESC		*rgColumnDesc	= NULL;
	DBORDINAL			cColumnDesc		= 0;
	ULONG				cPropSet		= 0;
	DBPROPSET			*prgPropSet		= NULL;
	DBPROPSET			rgPropSet[1];
	DBPROP				rgProp[1];

	DuplicateColumnDesc(m_rgColumnDesc, m_cColumnDesc, &rgColumnDesc);
	cColumnDesc = m_cColumnDesc;
	ReleaseAllColumnPropSets(rgColumnDesc, cColumnDesc);

	// create a table and open a bookmark rowset on it
	if (SettableProperty(DBPROP_BOOKMARKS, DBPROPSET_ROWSET))
	{
		FILL_PROP_SET(rgPropSet[0], 1, rgProp, DBPROPSET_ROWSET);
		FILL_PROP(rgProp[0], DBPROP_BOOKMARKS, VT_BOOL, V_BOOL, VARIANT_TRUE, DBPROPOPTIONS_REQUIRED);
		prgPropSet	= rgPropSet;
		cPropSet	= 1;
	}
	TEST2C_(hr = CreateAndCheckTable(m_pITableDefinition, &Aggregate, NULL, cColumnDesc, rgColumnDesc, IID_IUnknown, cPropSet, prgPropSet,
		&pTableID, (IUnknown**)&Aggregate.m_pIUnkInner), S_OK, DB_E_NOAGGREGATION);
	TEST_PROVIDER(S_OK == hr);

	//Verify Aggregation for this rowset...
	TESTC(Aggregate.VerifyAggregationQI(hr, IID_IRowsetInfo, (IUnknown**)&pIRowsetInfo));

	//Verify we are hooked up...
	//This call we are using the Rowset and asking for IID_IAggregate, 
	//which is the outer object and should succeed!!!  Kind of cool huh!
	hr = pIRowsetInfo->GetReferencedRowset(0, IID_IAggregate, (IUnknown**)&pIAggregate);
	TESTC(hr==S_OK || hr==DB_E_BADORDINAL ||hr==DB_E_NOTAREFERENCECOLUMN);
	if(hr==DB_E_NOTAREFERENCECOLUMN || hr==DB_E_BADORDINAL)
		TESTC(!GetProperty(DBPROP_BOOKMARKS, DBPROPSET_ROWSET, Aggregate.m_pIUnkInner, VARIANT_TRUE));
	TESTC_PROVIDER(hr==S_OK);	

	//Now make sure the Rowset QI for IUnknown give me the outer
	TESTC_(hr = pIRowsetInfo->GetReferencedRowset(0, IID_IUnknown, (IUnknown**)&pIUnkOuter),S_OK);
	TESTC(VerifyEqualInterface(pIAggregate, pIUnkOuter));

CLEANUP:
	SAFE_RELEASE(pIAggregate);
	SAFE_RELEASE(pIRowsetInfo);
	SAFE_RELEASE(pIUnkOuter);
	Aggregate.ReleaseInner();
	// checkings, etc
	CHECK(DropTableAndCheck(pTableID), S_OK);
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(72)
//*-----------------------------------------------------------------------
// @mfunc Agg session -> IRowsetInfo::GetSpecification
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCCreateTable::Variation_72()
{ 
    CAggregate			Aggregate(g_pIDBCreateSession);
	ULONG				fTestRes			= TEST_FAIL;
    IRowsetInfo			*pIRowsetInfo		= NULL;
    ITableDefinition	*pITableDefinition	= NULL;
	IUnknown			*pIAggregate		= NULL;
	ULONG				ulRefCountBefore;
	ULONG				ulRefCountAfter;
	DBCOLUMNDESC		*rgColumnDesc		= NULL;
	DBORDINAL			cColumnDesc			= 0;
	DBID				*pTableID			= NULL;

	DuplicateColumnDesc(m_rgColumnDesc, m_cColumnDesc, &rgColumnDesc);
	cColumnDesc = m_cColumnDesc;
	ReleaseAllColumnPropSets(rgColumnDesc, cColumnDesc);

	//Aggregation
	HRESULT hr = CreateNewSession(g_pIDBInitialize, IID_IUnknown, (IUnknown**)&Aggregate.m_pIUnkInner, &Aggregate);

	TEST_PROVIDER(S_OK == hr);

	//Verify Aggregation for this session...
	TESTC(Aggregate.VerifyAggregationQI(hr, IID_ITableDefinition, (IUnknown**)&pITableDefinition));
	
	//Now Create the Rowset
	ulRefCountBefore = Aggregate.GetRefCount();
	// create a table and open a bookmark rowset on it
	TESTC_(CreateAndCheckTable(pITableDefinition, NULL, NULL, cColumnDesc, rgColumnDesc, 
		IID_IRowsetInfo, 0, NULL, &pTableID, (IUnknown**)&pIRowsetInfo), S_OK);
	ulRefCountAfter = Aggregate.GetRefCount();

	//GetSpecification
	TEST2C_(hr = pIRowsetInfo->GetSpecification(IID_IAggregate, (IUnknown**)&pIAggregate),S_OK,S_FALSE);

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

		//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"IRowsetInfo::GetSpecification unable to retrieve Parent object!");
	}

	fTestRes = TEST_PASS;

CLEANUP:
	SAFE_RELEASE(pIAggregate);
	SAFE_RELEASE(pIRowsetInfo);
	Aggregate.ReleaseInner();
	// checkings, etc
	if (pITableDefinition)
		CHECK(DropTableAndCheck(pTableID, pITableDefinition), S_OK);
	SAFE_RELEASE(pITableDefinition);
	return fTestRes;
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(73)
//*-----------------------------------------------------------------------
// @mfunc Table -> Agg ColumnRowset, ask for non IID_IUnknown
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCCreateTable::Variation_73()
{ 
	TBEGIN
	DBID				*pTableID			= NULL;
	CAggregate			Aggregate(m_pIOpenRowset);
	IRowset				*pIRowset			= NULL;
	IColumnsRowset		*pIColumnsRowset	= NULL;
	DBCOLUMNDESC		*rgColumnDesc		= NULL;
	DBORDINAL			cColumnDesc			= 0;
	DBPROPSET			*rgPropSet			= NULL;
	ULONG				cPropSet			= 0;

	DuplicateColumnDesc(m_rgColumnDesc, m_cColumnDesc, &rgColumnDesc);
	cColumnDesc = m_cColumnDesc;
	ReleaseAllColumnPropSets(rgColumnDesc, cColumnDesc);

	SetSettableProperty(DBPROP_IColumnsRowset, DBPROPSET_ROWSET, &cPropSet, &rgPropSet);
	TESTC_(CreateAndCheckTable(m_pITableDefinition, NULL, NULL, cColumnDesc, rgColumnDesc, 
		IID_IRowset, cPropSet, rgPropSet, &pTableID, (IUnknown**)&pIRowset), S_OK);

	//Obtain the ColumnsRowset interface [OPTIONAL] interface
	TESTC_PROVIDER(VerifyInterface(pIRowset, IID_IColumnsRowset, ROWSET_INTERFACE, (IUnknown**)&pIColumnsRowset));

	//Try to obtain anything but IID_IUnknown.  
	//This should fail, this is a requirement for COM Aggregation...
	TESTC_(pIColumnsRowset->GetColumnsRowset(&Aggregate, 0, NULL, IID_IRowset, 0, NULL, 
		(IUnknown**)&Aggregate.m_pIUnkInner),DB_E_NOAGGREGATION);

	//Inner object cannot RefCount the outer object - COM rule for CircularRef
	TESTC(Aggregate.GetRefCount() == 1);
	TESTC(Aggregate.m_pIUnkInner == NULL);
	

CLEANUP:
	SAFE_RELEASE(pIColumnsRowset);
	SAFE_RELEASE(pIRowset);	
	Aggregate.ReleaseInner();
	DropTableAndCheck(pTableID);
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(74)
//*-----------------------------------------------------------------------
// @mfunc Table -> Agg ColumnRowset, ask for IID_IUnknown
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCCreateTable::Variation_74()
{ 
	TBEGIN
	HRESULT				hr;
	DBID				*pTableID			= NULL;
	CAggregate			Aggregate(m_pIOpenRowset);
	IRowset				*pIRowset			= NULL;
	IColumnsRowset		*pIColumnsRowset	= NULL;
	DBCOLUMNDESC		*rgColumnDesc		= NULL;
	DBORDINAL			cColumnDesc			= 0;
	DBPROPSET			*rgPropSet			= NULL;
	ULONG				cPropSet			= 0;

	DuplicateColumnDesc(m_rgColumnDesc, m_cColumnDesc, &rgColumnDesc);
	cColumnDesc = m_cColumnDesc;
	ReleaseAllColumnPropSets(rgColumnDesc, cColumnDesc);

	SetSettableProperty(DBPROP_IColumnsRowset, DBPROPSET_ROWSET, &cPropSet, &rgPropSet);
	TEST2C_(hr = CreateAndCheckTable(m_pITableDefinition, NULL, NULL, cColumnDesc, rgColumnDesc, 
		IID_IRowset, cPropSet, rgPropSet, &pTableID, (IUnknown**)&pIRowset), S_OK, DB_E_ERRORSOCCURRED);

	if (DB_E_ERRORSOCCURRED == hr)
		TESTC(!GetProperty(DBPROP_IColumnsRowset, DBPROPSET_ROWSET, pIRowset, VARIANT_TRUE));
	TESTC_PROVIDER(S_OK == hr);

	//Obtain the ColumnsRowset interface [OPTIONAL] interface
	TESTC_PROVIDER(VerifyInterface(pIRowset, IID_IColumnsRowset, ROWSET_INTERFACE, (IUnknown**)&pIColumnsRowset));

	//Try to obtain IID_IUnknown.  
	TEST2C_(hr = pIColumnsRowset->GetColumnsRowset(&Aggregate, 0, NULL, IID_IUnknown, 0, NULL, 
		(IUnknown**)&Aggregate.m_pIUnkInner), S_OK, DB_E_NOAGGREGATION);
	TESTC_PROVIDER(S_OK == hr);	
	//Verify Aggregation for this session...
	TESTC(Aggregate.VerifyAggregationQI(hr, IID_IRowset));

CLEANUP:
	SAFE_RELEASE(pIColumnsRowset);
	SAFE_RELEASE(pIRowset);	
	Aggregate.ReleaseInner();
	// checkings, etc
	DropTableAndCheck(pTableID);
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(75)
//*-----------------------------------------------------------------------
// @mfunc Table -> Agg ColumnRowset -> IRowsetInfo::GetSpecification
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCCreateTable::Variation_75()
{ 
	TBEGIN
    CAggregate		Aggregate(m_pIOpenRowset);
	ULONG			fTestRes			= TEST_FAIL;
    IRowset			*pIRowset			= NULL;
    IColumnsRowset	*pIColumnsRowset	= NULL;
	IUnknown		*pIAggregate		= NULL;
	IRowsetInfo		*pIRowsetInfo		= NULL;
	ULONG			ulRefCountBefore;
	ULONG			ulRefCountAfter;
	HRESULT			hr					= S_OK;
	DBCOLUMNDESC	*rgColumnDesc		= NULL;
	DBORDINAL		cColumnDesc			= 0;
	DBPROPSET		*rgPropSet			= NULL;
	ULONG			cPropSet			= 0;
	DBID			*pTableID			= NULL;
	BOOL			fCreatedTable		= FALSE;

	DuplicateColumnDesc(m_rgColumnDesc, m_cColumnDesc, &rgColumnDesc);
	cColumnDesc = m_cColumnDesc;
	ReleaseAllColumnPropSets(rgColumnDesc, cColumnDesc);

	SetSettableProperty(DBPROP_IColumnsRowset, DBPROPSET_ROWSET, &cPropSet, &rgPropSet);
	TEST3C_(hr = CreateAndCheckTable(m_pITableDefinition, &Aggregate, NULL, cColumnDesc, rgColumnDesc, 
		IID_IUnknown, cPropSet, rgPropSet, &pTableID, (IUnknown**)&Aggregate.m_pIUnkInner),
		S_OK, DB_E_ERRORSOCCURRED, DB_E_NOAGGREGATION);

	if (DB_E_ERRORSOCCURRED == hr)
		TESTC(!GetProperty(DBPROP_IColumnsRowset, DBPROPSET_ROWSET, pIRowset, VARIANT_TRUE));

	TESTC_PROVIDER(S_OK == hr);
	fCreatedTable = TRUE;

	//Verify Aggregation
	TESTC(Aggregate.VerifyAggregationQI(hr, IID_IRowset, (IUnknown**)&pIRowset));

	//Obtain the ColumnsRowset interface [OPTIONAL] interface
	TESTC_PROVIDER(VerifyInterface(pIRowset, IID_IColumnsRowset, ROWSET_INTERFACE, (IUnknown**)&pIColumnsRowset));

	//IColumnsRowset::GetRowset
	ulRefCountBefore = Aggregate.GetRefCount();
	TESTC_(hr = pIColumnsRowset->GetColumnsRowset(NULL, 0, NULL, IID_IRowsetInfo, 0, NULL, (IUnknown**)&pIRowsetInfo),S_OK);
	ulRefCountAfter = Aggregate.GetRefCount();

	//GetSpecification
	TEST2C_(hr = pIRowsetInfo->GetSpecification(IID_IAggregate, (IUnknown**)&pIAggregate),S_OK,S_FALSE);

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

		//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"IRowsetInfo::GetSpecification unable to retrieve Parent object!");
	}

CLEANUP:
	SAFE_RELEASE(pIRowsetInfo);
	SAFE_RELEASE(pIAggregate);
	SAFE_RELEASE(pIColumnsRowset);
	SAFE_RELEASE(pIRowset);
	Aggregate.ReleaseInner();
	// checkings, etc
	CHECK(DropTableAndCheck(pTableID), fCreatedTable? S_OK : E_INVALIDARG);
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(76)
//*-----------------------------------------------------------------------
// @mfunc colid is ignored in a non column specific rowset property
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCCreateTable::Variation_76()
{ 
	TBEGIN
	DBPROPSET		rgPropSet[1];
	DBPROP			rgProp[1];
	DBPROPID		dwPropID;
	DBCOLUMNDESC	*rgColumnDesc	= NULL;
	DBORDINAL		cColumnDesc		= 0;
	HRESULT			hr;
	DBPROPSTATUS	dwStatus;

	// make sure there is a non column specific rowset property that is settable
	TESTC_PROVIDER(GetNonColSpecProp(DBPROPSET_ROWSET, &dwPropID));

	DuplicateColumnDesc(m_rgColumnDesc, m_cColumnDesc, &rgColumnDesc);
	cColumnDesc = m_cColumnDesc;
	ReleaseAllColumnPropSets(rgColumnDesc, cColumnDesc);

	rgColumnDesc[0].cPropertySets	= 0;
	rgColumnDesc[0].rgPropertySets	= NULL;

	FILL_PROP_SET(rgPropSet[0], 1, rgProp, DBPROPSET_ROWSET)
	FILL_PROP(rgProp[0], dwPropID, DBTYPE_BOOL, V_BOOL, 
		VARIANT_TRUE, DBPROPOPTIONS_OPTIONAL)

	// get the result with DB_NULLID
	hr = CCNDropTable(NULL, cColumnDesc, rgColumnDesc, IID_IRowset, 1, rgPropSet);

	dwStatus = rgProp[0].dwStatus;
	if (S_OK != hr)
	{
		TESTC_(hr, DB_S_ERRORSOCCURRED);
		TESTC(DBPROPSTATUS_NOTSUPPORTED == dwStatus);
	}
	else
	{
		TESTC(DBPROPSTATUS_OK == dwStatus);
	}

	// set colID to a value different from DB_NULLID	
	rgProp[0].colid.eKind			= DBKIND_NAME;
	rgProp[0].colid.uName.pwszName	= L"someColumn";

	// check colid is ignored for the rowset property
	TESTC_(CCNDropTable(NULL, cColumnDesc, rgColumnDesc, IID_IRowset, 1, rgPropSet), hr);
	TESTC(dwStatus == rgProp[0].dwStatus);

	// check colid is ignored for the column property
	rgProp[0].dwOptions = DBPROPOPTIONS_REQUIRED;
	CHECK(CCNDropTable(NULL, cColumnDesc, rgColumnDesc, IID_IRowset, 
		1, rgPropSet), S_OK == hr? S_OK: DB_E_ERRORSOCCURRED);
	TESTC(dwStatus == rgProp[0].dwStatus);

CLEANUP:
	ReleaseColumnDesc(rgColumnDesc, cColumnDesc);
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(77)
//*-----------------------------------------------------------------------
// @mfunc colid is DB_NULLID in a column specific rowset property => S_OK
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCCreateTable::Variation_77()
{ 
	TBEGIN
	DBPROPSET		rgPropSet[1];
	DBPROP			rgProp[1];
	DBPROPID		dwPropID;
	DBCOLUMNDESC	*rgColumnDesc	= NULL;
	DBORDINAL		cColumnDesc		= 0;
	HRESULT			hr;

	// make sure there is a column specific rowset property that is settable
	TESTC_PROVIDER(GetColSpecProp(DBPROPSET_ROWSET, &dwPropID));

	DuplicateColumnDesc(m_rgColumnDesc, m_cColumnDesc, &rgColumnDesc);
	cColumnDesc = m_cColumnDesc;
	ReleaseAllColumnPropSets(rgColumnDesc, cColumnDesc);

	rgColumnDesc[0].cPropertySets	= 0;
	rgColumnDesc[0].rgPropertySets	= NULL;

	FILL_PROP_SET(rgPropSet[0], 1, rgProp, DBPROPSET_ROWSET)
	FILL_PROP(rgProp[0], dwPropID, DBTYPE_BOOL, V_BOOL, 
		VARIANT_TRUE, DBPROPOPTIONS_OPTIONAL)

	// explicitly set colID to DB_NULLID	
	rgProp[0].colid = DB_NULLID;

	// check colid is ignored for the rowset property
	hr = CCNDropTable(NULL, cColumnDesc, rgColumnDesc, IID_IRowset, 1, rgPropSet);
	if (DB_S_ERRORSOCCURRED == hr)
	{
		TESTC(DBPROPSTATUS_NOTALLSETTABLE == rgProp[0].dwStatus);
	}
	else
	{
		TESTC_(hr, S_OK);
		TESTC(DBPROPSTATUS_OK == rgProp[0].dwStatus);
	}

	// check colid is ignored for the column property
	rgProp[0].dwOptions = DBPROPOPTIONS_REQUIRED;
	// check colid is ignored for the rowset property
	hr = CCNDropTable(NULL, cColumnDesc, rgColumnDesc, IID_IRowset, 1, rgPropSet);
	if (DB_E_ERRORSOCCURRED == hr)
	{
		TESTC(DBPROPSTATUS_NOTALLSETTABLE == rgProp[0].dwStatus);
	}
	else
	{
		TESTC_(hr, S_OK);
		TESTC(DBPROPSTATUS_OK == rgProp[0].dwStatus);
	}


CLEANUP:
	ReleaseColumnDesc(rgColumnDesc, cColumnDesc);
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(78)
//*-----------------------------------------------------------------------
// @mfunc valid, non DB_NULLID colid for a column specific rowset property
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCCreateTable::Variation_78()
{ 
	TBEGIN
	DBPROPSET		rgPropSet[1];
	DBPROP			rgProp[1];
	DBPROPID		dwPropID;
	DBCOLUMNDESC	*rgColumnDesc	= NULL;
	DBORDINAL		cColumnDesc		= 0;

	memset(&rgProp[0].colid, 0, sizeof(DBID));

	// make sure there is a column specific rowset property that is settable
	TESTC_PROVIDER(GetColSpecProp(DBPROPSET_ROWSET, &dwPropID));

	DuplicateColumnDesc(m_rgColumnDesc, m_cColumnDesc, &rgColumnDesc);
	cColumnDesc = m_cColumnDesc;
	ReleaseAllColumnPropSets(rgColumnDesc, cColumnDesc);

	rgColumnDesc[0].cPropertySets	= 0;
	rgColumnDesc[0].rgPropertySets	= NULL;

	FILL_PROP_SET(rgPropSet[0], 1, rgProp, DBPROPSET_ROWSET)
	FILL_PROP(rgProp[0], dwPropID, DBTYPE_BOOL, V_BOOL, 
		VARIANT_TRUE, DBPROPOPTIONS_OPTIONAL)

	// explicitly set colID to DB_NULLID	
	DuplicateDBID(m_rgColumnDesc[0].dbcid, &rgProp[0].colid);

	// check colid is ignored for the rowset property
	CHECK(CCNDropTable(NULL, cColumnDesc, rgColumnDesc, IID_IRowset, 1, rgPropSet), S_OK);
	COMPARE(DBPROPSTATUS_OK == rgProp[0].dwStatus, TRUE);

	// check colid is ignored for the column property
	rgProp[0].dwOptions = DBPROPOPTIONS_REQUIRED;
	// check colid is ignored for the rowset property
	CHECK(CCNDropTable(NULL, cColumnDesc, rgColumnDesc, IID_IRowset, 1, rgPropSet), S_OK);
	COMPARE(DBPROPSTATUS_OK == rgProp[0].dwStatus, TRUE);

CLEANUP:
	ReleaseDBID(&rgProp[0].colid, FALSE);
	ReleaseColumnDesc(rgColumnDesc, cColumnDesc);
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(79)
//*-----------------------------------------------------------------------
// @mfunc invalid colid for a column specific rowset property
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCCreateTable::Variation_79()
{ 
	TBEGIN
	DBPROPSET		rgPropSet[1];
	DBPROP			rgProp[1];
	DBPROPID		dwPropID;
	DBCOLUMNDESC	*rgColumnDesc	= NULL;
	DBORDINAL		cColumnDesc		= 0;

	// make sure there is a column specific rowset property that is settable
	TESTC_PROVIDER(GetColSpecProp(DBPROPSET_ROWSET, &dwPropID));

	DuplicateColumnDesc(m_rgColumnDesc, m_cColumnDesc, &rgColumnDesc);
	cColumnDesc = m_cColumnDesc;
	ReleaseAllColumnPropSets(rgColumnDesc, cColumnDesc);

	rgColumnDesc[0].cPropertySets	= 0;
	rgColumnDesc[0].rgPropertySets	= NULL;

	FILL_PROP_SET(rgPropSet[0], 1, rgProp, DBPROPSET_ROWSET)
	FILL_PROP(rgProp[0], dwPropID, DBTYPE_BOOL, V_BOOL, 
		VARIANT_TRUE, DBPROPOPTIONS_OPTIONAL)

	// set colID to a value different from DB_NULLID	
	rgProp[0].colid.eKind			= DBKIND_NAME;
	rgProp[0].colid.uName.pwszName	= L"someColumn";

	// check colid is ignored for the rowset property
	CHECK(CCNDropTable(NULL, cColumnDesc, rgColumnDesc, IID_IRowset, 1, rgPropSet), DB_S_ERRORSOCCURRED);
	COMPARE(DBPROPSTATUS_BADCOLUMN == rgProp[0].dwStatus, TRUE);

	// check colid is ignored for the column property
	rgProp[0].dwOptions = DBPROPOPTIONS_REQUIRED;
	CHECK(CCNDropTable(NULL, cColumnDesc, rgColumnDesc, IID_IRowset, 1, rgPropSet), DB_E_ERRORSOCCURRED);
	COMPARE(DBPROPSTATUS_BADCOLUMN == rgProp[0].dwStatus, TRUE);

CLEANUP:
	ReleaseColumnDesc(rgColumnDesc, cColumnDesc);
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(80)
//*-----------------------------------------------------------------------
// @mfunc Create a table. Retrieve a rowset on it (IRowsetInfo). Check GetSpecification()
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCCreateTable::Variation_80()
{ 
	IRowsetInfo				*pIRowsetInfo	= NULL;
	IOpenRowset				*pIOpenRowset	= NULL;
	BOOL					fTestRes		= TEST_FAIL;
	DBID					*pTableID		= NULL;
	DBCOLUMNDESC			*rgColumnDesc	= NULL;
	DBORDINAL				cColumnDesc		= 0;
	HRESULT					hr;

	DuplicateColumnDesc(m_rgColumnDesc, m_cColumnDesc, &rgColumnDesc);
	cColumnDesc = m_cColumnDesc;

	TESTC_(CreateAndCheckTable(m_pITableDefinition, NULL, NULL, cColumnDesc, rgColumnDesc, IID_IRowsetInfo, 
		0, NULL, &pTableID, (IUnknown**)&pIRowsetInfo), S_OK);

	hr = pIRowsetInfo->GetSpecification(IID_IOpenRowset, (IUnknown**)&pIOpenRowset);
	if (S_FALSE != hr)
	{
		TESTC_(hr, S_OK);
		TESTC(VerifyEqualInterface(m_pITableDefinition, pIOpenRowset));
	}

	fTestRes = TEST_PASS;
	
CLEANUP:
	SAFE_RELEASE(pIRowsetInfo);
	SAFE_RELEASE(pIOpenRowset);
	ReleaseColumnDesc(rgColumnDesc, cColumnDesc);
	if (pTableID)
		CHECK(DropTableAndCheck(pTableID), S_OK);
	ReleaseDBID(pTableID);
	return fTestRes;
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(81)
//*-----------------------------------------------------------------------
// @mfunc DB_NULLID is ignored for non column-related table properties
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCCreateTable::Variation_81()
{ 
	TBEGIN
	DBPROPSET		rgPropSets[1];
	DBPROP			rgProp[1];
	DBCOLUMNDESC	*rgColumnDesc	= NULL;
	DBORDINAL		cColumnDesc		= 0;
	DBPROPID		dwPropID;

	// make sure there is a non column specific rowset property that is settable
	TESTC_PROVIDER(GetNonColSpecProp(DBPROPSET_TABLE, &dwPropID));

	DuplicateColumnDesc(m_rgColumnDesc, m_cColumnDesc, &rgColumnDesc);
	cColumnDesc = m_cColumnDesc;
	ReleaseAllColumnPropSets(rgColumnDesc, cColumnDesc);

	FILL_PROP_SET(rgPropSets[0], NUMELEM(rgProp), rgProp, DBPROPSET_TABLE);
	FILL_PROP(rgProp[0], dwPropID, VT_BOOL, V_BOOL, 
		VARIANT_TRUE, DBPROPOPTIONS_REQUIRED);

	// setting a colid != DB_NULLID for a table property should result in error
	rgProp[0].colid.eKind		= DBKIND_NAME;
	rgProp[0].colid.uName.pwszName	= L"AliBaba";
	
	CHECK(CCNDropTable(NULL, cColumnDesc, rgColumnDesc, IID_IRowset, 
					NUMELEM(rgPropSets), rgPropSets), S_OK);

	// TableID generated by provider
	FILL_PROP(rgProp[0], dwPropID, VT_BOOL, V_BOOL, 
		VARIANT_FALSE, DBPROPOPTIONS_REQUIRED);
	TESTC_(CCNDropTable(NULL, cColumnDesc, rgColumnDesc, IID_IRowset, 
					NUMELEM(rgPropSets), rgPropSets), S_OK);
	
CLEANUP:
	// checkings, etc
	ReleaseColumnDesc(rgColumnDesc, cColumnDesc);
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(82)
//*-----------------------------------------------------------------------
// @mfunc Column related table property set to bad colid
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCCreateTable::Variation_82()
{ 
	TBEGIN
	DBPROPSET		rgPropSets[1];
	DBPROP			rgProp[1];
	DBCOLUMNDESC	*rgColumnDesc	= NULL;
	DBORDINAL		cColumnDesc		= 0;
	DBPROPID		dwPropID;

	// make sure there is a non column specific rowset property that is settable
	TESTC_PROVIDER(GetColSpecProp(DBPROPSET_TABLE, &dwPropID));

	DuplicateColumnDesc(m_rgColumnDesc, m_cColumnDesc, &rgColumnDesc);
	cColumnDesc = m_cColumnDesc;
	ReleaseAllColumnPropSets(rgColumnDesc, cColumnDesc);

	FILL_PROP_SET(rgPropSets[0], NUMELEM(rgProp), rgProp, DBPROPSET_TABLE);
	FILL_PROP(rgProp[0], dwPropID, VT_BOOL, V_BOOL, 
		VARIANT_TRUE, DBPROPOPTIONS_REQUIRED);

	// setting a colid != DB_NULLID for a table property should result in error
	rgProp[0].colid.eKind		= DBKIND_NAME;
	rgProp[0].colid.uName.pwszName	= L"AliBaba";
	
	TESTC_(CCNDropTable(NULL, cColumnDesc, rgColumnDesc, IID_IRowset, 
					NUMELEM(rgPropSets), rgPropSets), DB_S_ERRORSOCCURRED);

	// TableID generated by provider
	FILL_PROP(rgProp[0], dwPropID, VT_BOOL, V_BOOL, 
		VARIANT_FALSE, DBPROPOPTIONS_REQUIRED);
	TESTC_(CCNDropTable(NULL, cColumnDesc, rgColumnDesc, IID_IRowset, 
					NUMELEM(rgPropSets), rgPropSets), DB_E_ERRORSOCCURRED);
	
CLEANUP:
	// checkings, etc
	ReleaseColumnDesc(rgColumnDesc, cColumnDesc);
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(83)
//*-----------------------------------------------------------------------
// @mfunc How many DBTYPE_I4 columns?
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCCreateTable::Variation_83()
{ 
	return TEST_PASS;
	/*
	TBEGIN
	CTable			*pCTable		= new CTable(m_pThisTestModule->m_pIUnknown2, 
										(LPWSTR)gwszModuleName);
	DBTYPE			dbType			= DBTYPE_I4;
	BYTE			precision		= 0;
	BYTE			scale			= 0;
	HRESULT			hr;
	DBCOLUMNDESC	*rgColumnDesc	= NULL;
	const ULONG		MAX_VAL			= 2048;
	ULONG			cColumnDesc		= MAX_VAL / 2;
	ULONG			iCol;
	ULONG			offset			= MAX_VAL / 4;

	pCTable->SetBuildColumnDesc(FALSE);
	for (;0 < offset;)
	{
		SAFE_ALLOC(rgColumnDesc, DBCOLUMNDESC, cColumnDesc);
		memset(rgColumnDesc, 0, cColumnDesc*sizeof(DBCOLUMNDESC));
		for (iCol = 0; iCol < cColumnDesc; iCol++)
		{
			// fill in a column
			rgColumnDesc[iCol].wType					= dbType;
			rgColumnDesc[iCol].bPrecision				= precision;
			rgColumnDesc[iCol].bScale					= scale;
			rgColumnDesc[iCol].dbcid.eKind				= DBKIND_NAME;
			SAFE_ALLOC(rgColumnDesc[iCol].dbcid.uName.pwszName, WCHAR, 10);
			swprintf(rgColumnDesc[iCol].dbcid.uName.pwszName, L"C%dCol", iCol);
		}

		pCTable->SetColumnDesc(rgColumnDesc, cColumnDesc);
		hr = pCTable->CreateTable(100, 0);
		if (SUCCEEDED(hr))
		{
			pCTable->DropTable();
			if (cColumnDesc < MAX_VAL)
				cColumnDesc += offset;
			else
				break;
		}
		else
		{
			if (cColumnDesc < offset)
				break;
			cColumnDesc -= offset;
		}
		offset /= 2;
	}
	odtLog << "Max no of columns : " << cColumnDesc << "\n";

CLEANUP:
	pCTable->DropTable();

	SAFE_DELETE(pCTable);
	TRETURN
	*/
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(84)
//*-----------------------------------------------------------------------
// @mfunc Open a rowset with CE, call IColumnRowset with an aggregated pIUnk
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCCreateTable::Variation_84()
{
	TBEGIN
	IRowsetFind		*pIRowsetFind	= NULL;
	IColumnsRowset	*pIColumnsRowset= NULL;
	DBID			*pTableID		= NULL;
	DBCOLUMNDESC	*rgColumnDesc	= NULL;
	DBORDINAL		cColumnDesc		= 0;
	HRESULT			hr;
	CAggregate		Aggregate(NULL);

	TESTC_PROVIDER(SettableProperty(DBPROP_IRowsetFind, DBPROPSET_ROWSET));
	DuplicateColumnDesc(m_rgColumnDesc, m_cColumnDesc, &rgColumnDesc);
	cColumnDesc = m_cColumnDesc;

	TEST2C_(hr = CreateAndCheckTable(m_pITableDefinition, NULL, NULL, cColumnDesc, rgColumnDesc, 
		IID_IRowsetFind, 0, NULL, &pTableID, (IUnknown**)&pIRowsetFind), S_OK, E_NOINTERFACE);

	TESTC_PROVIDER(S_OK == hr);

	TESTC_(pIRowsetFind->QueryInterface(IID_IColumnsRowset, (LPVOID*)&pIColumnsRowset), S_OK);
	TESTC_(hr = pIColumnsRowset->GetColumnsRowset(&Aggregate, 0, NULL, IID_IUnknown,
		0, NULL, (IUnknown**)&Aggregate.m_pIUnkInner), S_OK);
	
	// Verify Aggregation for this rowset...
	TESTC(Aggregate.VerifyAggregationQI(hr, IID_IRowset));

CLEANUP:
	Aggregate.ReleaseInner();
	SAFE_RELEASE(pIRowsetFind);
	SAFE_RELEASE(pIColumnsRowset);
	ReleaseColumnDesc(rgColumnDesc, cColumnDesc);
	if (pTableID)
		CHECK(DropTableAndCheck(pTableID), S_OK);
	ReleaseDBID(pTableID);
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(85)
//*-----------------------------------------------------------------------
// @mfunc Different DBKINDs for pTableID
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCCreateTable::Variation_85()
{ 
	TBEGIN
	LPWSTR			pwszColumnName = NULL;
	DBCOLUMNDESC	*rgColumnDesc	= NULL;
	DBORDINAL		cColumnDesc		= 0;
	DBID			TableID;
	HRESULT			hr;
//	DBKIND_GUID_NAME
//	DBKIND_GUID_PROPID
//	DBKIND_NAME
//	DBKIND_PGUID_NAME
//	DBKIND_PGUID_PROPID
//	DBKIND_PROPID
//	DBKIND_GUID 

	m_pTable->MakeTableName(NULL);
	
	DuplicateColumnDesc(m_rgColumnDesc, m_cColumnDesc, &rgColumnDesc);
	cColumnDesc = m_cColumnDesc;
	ReleaseAllColumnPropSets(rgColumnDesc, cColumnDesc);

	TableID.eKind = DBKIND_NAME;
	TableID.uName.pwszName	= m_pTable->GetTableName();
	TEST2C_(hr = CCNDropTable(&TableID, cColumnDesc, rgColumnDesc, IID_IUnknown, 
		0, NULL, TRUE), S_OK, DB_E_BADTABLEID);

	TableID.eKind			= DBKIND_GUID_NAME;
	TableID.uGuid.guid		= guidModule;
	m_pTable->MakeTableName(NULL);
	TableID.uName.pwszName	= m_pTable->GetTableName();
	TEST2C_(CCNDropTable(&TableID, cColumnDesc, rgColumnDesc, IID_IRowset, 0, NULL, TRUE), S_OK, DB_E_BADTABLEID);

	TableID.eKind			= DBKIND_PGUID_NAME;
	TableID.uGuid.pguid		= &guidModule;
	m_pTable->MakeTableName(NULL);
	TableID.uName.pwszName	= m_pTable->GetTableName();
	TEST2C_(CCNDropTable(&TableID, cColumnDesc, rgColumnDesc, IID_IRowset, 0, NULL, TRUE), S_OK, DB_E_BADTABLEID);

	TableID.eKind			= DBKIND_GUID;
	TableID.uGuid.guid		= guidModule;
	m_pTable->MakeTableName(NULL);
	TableID.uName.pwszName	= m_pTable->GetTableName();
	TEST2C_(CCNDropTable(&TableID, cColumnDesc, rgColumnDesc, IID_IRowset, 0, NULL, TRUE), S_OK, DB_E_BADTABLEID);

	TableID.eKind			= DBKIND_GUID_PROPID;
	TableID.uGuid.guid		= guidModule;
	TableID.uName.ulPropid	= 0xffL;
	TEST2C_(CCNDropTable(&TableID, cColumnDesc, rgColumnDesc, IID_IRowset, 0, NULL, TRUE), S_OK, DB_E_BADTABLEID);

	TableID.eKind			= DBKIND_PGUID_PROPID;
	TableID.uGuid.pguid		= &guidModule;
	TableID.uName.ulPropid	= 0xffL;
	TEST2C_(CCNDropTable(&TableID, cColumnDesc, rgColumnDesc, IID_IRowset, 0, NULL, TRUE), S_OK, DB_E_BADTABLEID);

	TableID.eKind			= DBKIND_PROPID;
	TableID.uGuid.pguid		= &guidModule;
	TableID.uName.ulPropid	= 0xffL;
	TEST2C_(CCNDropTable(&TableID, cColumnDesc, rgColumnDesc, IID_IRowset, 0, NULL, TRUE), S_OK, DB_E_BADTABLEID);

CLEANUP:
	ReleaseColumnDesc(rgColumnDesc, cColumnDesc);
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(86)
//*-----------------------------------------------------------------------
// @mfunc Different DBKINDs for column IDs
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCCreateTable::Variation_86()
{ 
	TBEGIN
	LPWSTR	pwszColumnName = NULL;
	DBCOLUMNDESC	*rgColumnDesc	= NULL;
	DBORDINAL		cColumnDesc		= 0;
//	DBKIND_GUID_NAME
//	DBKIND_GUID_PROPID
//	DBKIND_NAME
//	DBKIND_PGUID_NAME
//	DBKIND_PGUID_PROPID
//	DBKIND_PROPID
//	DBKIND_GUID 

	DuplicateColumnDesc(m_rgColumnDesc, m_cColumnDesc, &rgColumnDesc);
	cColumnDesc = m_cColumnDesc;
	ReleaseAllColumnPropSets(rgColumnDesc, cColumnDesc);

	pwszColumnName = rgColumnDesc[0].dbcid.uName.pwszName;

	rgColumnDesc[0].dbcid.eKind = DBKIND_NAME;
	rgColumnDesc[0].dbcid.uName.pwszName	= pwszColumnName;
	TEST2C_(CCNDropTable(NULL, cColumnDesc, rgColumnDesc, IID_IRowset, 0, NULL), S_OK, DB_E_BADCOLUMNID);

	rgColumnDesc[0].dbcid.eKind				= DBKIND_GUID_NAME;
	rgColumnDesc[0].dbcid.uGuid.guid		= guidModule;
	rgColumnDesc[0].dbcid.uName.pwszName	= pwszColumnName;
	TEST2C_(CCNDropTable(NULL, cColumnDesc, rgColumnDesc, IID_IRowset, 0, NULL), S_OK, DB_E_BADCOLUMNID);

	rgColumnDesc[0].dbcid.eKind				= DBKIND_PGUID_NAME;
	rgColumnDesc[0].dbcid.uGuid.pguid		= &guidModule;
	rgColumnDesc[0].dbcid.uName.pwszName	= pwszColumnName;
	TEST2C_(CCNDropTable(NULL, cColumnDesc, rgColumnDesc, IID_IRowset, 0, NULL), S_OK, DB_E_BADCOLUMNID);

	rgColumnDesc[0].dbcid.eKind				= DBKIND_GUID;
	rgColumnDesc[0].dbcid.uGuid.guid		= guidModule;
	rgColumnDesc[0].dbcid.uName.pwszName	= pwszColumnName;
	TEST2C_(CCNDropTable(NULL, cColumnDesc, rgColumnDesc, IID_IRowset, 0, NULL), S_OK, DB_E_BADCOLUMNID);

	rgColumnDesc[0].dbcid.eKind				= DBKIND_GUID_PROPID;
	rgColumnDesc[0].dbcid.uGuid.guid		= guidModule;
	rgColumnDesc[0].dbcid.uName.ulPropid	= 0xffL;
	TEST2C_(CCNDropTable(NULL, cColumnDesc, rgColumnDesc, IID_IRowset, 0, NULL), S_OK, DB_E_BADCOLUMNID);

	rgColumnDesc[0].dbcid.eKind				= DBKIND_PGUID_PROPID;
	rgColumnDesc[0].dbcid.uGuid.pguid		= &guidModule;
	rgColumnDesc[0].dbcid.uName.ulPropid	= 0xffL;
	TEST2C_(CCNDropTable(NULL, cColumnDesc, rgColumnDesc, IID_IRowset, 0, NULL), S_OK, DB_E_BADCOLUMNID);

	rgColumnDesc[0].dbcid.eKind				= DBKIND_PROPID;
	rgColumnDesc[0].dbcid.uGuid.pguid		= &guidModule;
	rgColumnDesc[0].dbcid.uName.ulPropid	= 0xffL;
	TEST2C_(CCNDropTable(NULL, cColumnDesc, rgColumnDesc, IID_IRowset, 0, NULL), S_OK, DB_E_BADCOLUMNID);

	rgColumnDesc[0].dbcid.eKind = DBKIND_NAME;
	rgColumnDesc[0].dbcid.uName.pwszName	= pwszColumnName;
	ReleaseColumnDesc(rgColumnDesc, cColumnDesc);

CLEANUP:
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END


// {{ TCW_TERMINATE_METHOD
//--------------------------------------------------------------------
// @mfunc TestCase Termination Routine
//
// @rdesc TRUE or FALSE
//
BOOL TCCreateTable::Terminate()
{
	// {{ TCW_TERM_BASECLASS_CHECK2
	return(TCITableDefinition::Terminate());
}	// }}
// }}
// }}



// {{ TCW_TC_PROTOTYPE(RODataSource)
//*-----------------------------------------------------------------------
//| Test Case:		RODataSource - Test case for operating on a read only data source
//| Created:  	10/13/97
//*-----------------------------------------------------------------------

//*-----------------------------------------------------------------------
// @mfunc TestCase Initialization Routine
//
// @rdesc TRUE or FALSE
//
BOOL RODataSource::Init()
{
	BOOL			fResults		= TEST_SKIPPED;
	IDBInitialize	*pIDBInitialize	= NULL;
	IDBProperties	*pIDBProperties	= NULL;
	DBPROPSET		*rgPropSets		= NULL;
	ULONG			cPropSets		= 0;
	HRESULT			hr				= NOERROR;
	DBPROP			*rgProperties	= NULL;
	const int		n=1;
	const ULONG		nINIT_MODE = 0;
	DBPROPIDSET		rgPropIDSet[n];
	DBPROPID		rgPropID1[1];
	ULONG			nActualSize		= n;

	m_pIUnknown				= NULL;
	m_pIUnknown2			= NULL;
	m_pITableDefinition2	= NULL;
	m_pTable				= NULL; 

	// {{ TCW_INIT_BASECLASS_CHECK
	if(!TCDropColumn::Init())
	// }}
		goto CLEANUP2;

	if (!SettableProperty(DBPROP_INIT_MODE, DBPROPSET_DBINIT))
	{
		odtLog << "DBPROP_INIT_MODE is not supported or is not a read-write property\n";
		fResults = TEST_SKIPPED;
		goto CLEANUP2;
	}

	// create a spare table on the read-write datasource
	m_hr = m_pTable->CreateTable(10, 0);

	m_pITableDefinition2	= m_pITableDefinition;
	m_pITableDefinition		= NULL;
	fResults = FALSE;

	if (!CHECK(m_hr, S_OK)) 
	{
		odtLog << "could not create atable on the read-write data source!\n";
		goto CLEANUP;
	}

	// Setup the arrays needed for init, based on string LTM passed to us
	if(!GetInitProps(&cPropSets, &rgPropSets))
		goto CLEANUP;


	// Get our initial connection to the provider, asking for IDBInitialize since 
	// we must initialize before anything else
	if(!SUCCEEDED(m_hr = GetModInfo()->CreateProvider(NULL, IID_IDBInitialize, (IUnknown**)&pIDBInitialize)))
		goto CLEANUP;

	// Get IDBProperties Pointer
	pIDBProperties = NULL;
	if (!VerifyInterface(pIDBInitialize, IID_IDBProperties, DATASOURCE_INTERFACE, (IUnknown**)&pIDBProperties))
		goto CLEANUP;

	// Set the properties before we Initialize, only if we have Properties to set...
	if (FAILED(m_hr = pIDBProperties->SetProperties(cPropSets, rgPropSets)))
		goto CLEANUP;

	// free the structures
	FreeProperties(&cPropSets, &rgPropSets);
	rgPropSets	= NULL;
	cPropSets	= 0;
	SetProperty(&rgPropSets, &cPropSets, DBPROP_INIT_MODE, VT_I4, (LPVOID)DB_MODE_READ, DBPROPOPTIONS_REQUIRED, DB_NULLID, 
			DBPROPSET_DBINIT);
	// Set the properties before we Initialize, only if we have Properties to set...
	if (FAILED(m_hr = pIDBProperties->SetProperties(cPropSets, rgPropSets)))
	{
		FindProperty(
			DBPROP_INIT_MODE, 
			DBPROPSET_DBINIT, 
			cPropSets, 
			rgPropSets, 
			&rgProperties);
		if (DBPROPSTATUS_OK != rgProperties->dwStatus)
			odtLog << "Read only property could not be initialized!\n";
		goto CLEANUP1;
	}
	else
	{
		PRVTRACE("RODataSource::Init(): Apparently the read only property was set\n");
		FindProperty(
			DBPROP_INIT_MODE, 
			DBPROPSET_DBINIT, 
			cPropSets, 
			rgPropSets, 
			&rgProperties);
		if (DBPROPSTATUS_OK != rgProperties->dwStatus)
			odtLog << "ERROR: Read only property could not be initialized in fact!\n";
	}
	FreeProperties( &cPropSets, &rgPropSets);

	// Initialize
	if(!GCHECK(m_hr = pIDBInitialize->Initialize(), S_OK))
	{
		odtLog << wszInitializeFailed;	
		goto CLEANUP1;
	}

	// check that the read only property was set
	rgPropID1[0]							= DBPROP_INIT_MODE;
	rgPropIDSet[nINIT_MODE].cPropertyIDs	= 1;
	rgPropIDSet[nINIT_MODE].rgPropertyIDs	= rgPropID1;
	rgPropIDSet[nINIT_MODE].guidPropertySet	= DBPROPSET_DBINIT;

	CHECK(m_hr = pIDBProperties->GetProperties(nActualSize, rgPropIDSet, &cPropSets, &rgPropSets), S_OK);
	if (	(DBPROPSTATUS_OK == rgPropSets[nINIT_MODE].rgProperties[0].dwStatus) 
		&&	(	(VT_I4 != rgPropSets[nINIT_MODE].rgProperties[0].vValue.vt)
			||	(DB_MODE_READ != V_I4(&rgPropSets[nINIT_MODE].rgProperties[0].vValue))))
	{
		odtLog << "despite ok reports, DBPROP_INIT_MODE is not set to read only\n";
		goto CLEANUP1;
	}

	// Obtain IDBCreateSesson, placing the new DSO interface 
	// in CThisTestModule's m_pIUnknown, so that all testcases can use 
	// it via their back pointer to this object.  No need to call AddRef 
	// here as we will own it, rather than the test module.	 
	if (!VerifyInterface(pIDBInitialize, IID_IDBCreateSession, DATASOURCE_INTERFACE, 
			(IUnknown**)&m_pIUnknown))
		goto CLEANUP1;		
						 
	// Create a DB session object
	// Set the m_pIUnknown2 to IOpenRowset
	if (!GCHECK(((IDBCreateSession*)m_pIUnknown)->CreateSession(
			NULL, IID_IOpenRowset, (IUnknown **)&m_pIUnknown2), S_OK))	
		goto CLEANUP1;		

	SetDBSession(m_pIUnknown2);	// calls ReleaseDBSession Before
	// switch the interface on ItableDefinition
	if (!(m_hr=VerifyInterface(m_pIUnknown2, IID_ITableDefinition, SESSION_INTERFACE, 
		(IUnknown**)&m_pITableDefinition)))
		goto CLEANUP1;
	
	fResults = TRUE;
CLEANUP1:
	FreeProperties( &cPropSets, &rgPropSets);
CLEANUP:
	SAFE_RELEASE(pIDBProperties);
	SAFE_RELEASE(pIDBInitialize);
	return fResults;

CLEANUP2:
	if (m_pITableDefinition)
	{
		m_pITableDefinition2	= m_pITableDefinition;
		m_pITableDefinition		= NULL;
	}
	return fResults;
} 


// {{ TCW_VAR_PROTOTYPE(1)
//*-----------------------------------------------------------------------
// @mfunc Add a column
//
// @rdesc TEST_PASS or TEST_FAIL
//
int RODataSource::Variation_1()
{ 
	
	BOOL			fResults = TEST_PASS;
	DBID			*pColumnID = NULL;
	HRESULT			hr;
	DBCOLUMNDESC	*rgColumnDesc = NULL;
	DBORDINAL		cColumnDesc = m_pTable->CountColumnsOnTable();

	m_pTable->BuildColumnDescs(&rgColumnDesc);
	TESTC(0 < cColumnDesc);

	PROVIDER_FREE(rgColumnDesc->dbcid.uName.pwszName);
	FreeProperties( &rgColumnDesc->cPropertySets, &rgColumnDesc->rgPropertySets);
	rgColumnDesc[0].dbcid.uName.pwszName = wcsDuplicate(L"newColumn");
		
	if (!CHECK(hr = m_pITableDefinition->AddColumn(&m_pTable->GetTableID(), rgColumnDesc, &pColumnID), 
			DB_SEC_E_PERMISSIONDENIED))
		fResults = TEST_FAIL;

	ReleaseColumnDesc(rgColumnDesc, cColumnDesc);
CLEANUP:
	return fResults;
} 
// }} TCW_VAR_PROTOTYPE_END


// {{ TCW_VAR_PROTOTYPE(2)
//*-----------------------------------------------------------------------
// @mfunc Drop a column
//
// @rdesc TEST_PASS or TEST_FAIL
//
int RODataSource::Variation_2()
{ 
	TBEGIN;
	DBID			ColumnID;
	DBCOLUMNDESC	*oldCD			= NULL;
	DBORDINAL		oldlen			= 0;

	GetColumnDescOnTable(&m_pTable->GetTableID(), &oldCD, &oldlen);
	TESTC_PROVIDER(1 < oldlen);

	ColumnID.eKind			= DBKIND_NAME;
	ColumnID.uName.pwszName	= oldCD[0].dbcid.uName.pwszName;
	TEST2C_(DropColumnAndCheck(&m_pTable->GetTableID(), &ColumnID), S_OK, DB_SEC_E_PERMISSIONDENIED);

CLEANUP:
	ReleaseColumnDesc(oldCD, oldlen);
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END


// {{ TCW_VAR_PROTOTYPE(3)
//*-----------------------------------------------------------------------
// @mfunc Create a table
//
// @rdesc TEST_PASS or TEST_FAIL
//
int RODataSource::Variation_3()
{ 
	BOOL	fResults	= TEST_PASS;
	DBID	*pTableID	= NULL;

	if (!CHECK(m_pITableDefinition->CreateTable(NULL, NULL, m_cColumnDesc, m_rgColumnDesc, 
		IID_IRowset, 0, NULL, &pTableID, NULL), DB_SEC_E_PERMISSIONDENIED))
	{
		fResults = TEST_FAIL;
		m_pITableDefinition->DropTable(pTableID);
	}
	ReleaseDBID(pTableID);
	return fResults;
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(4)
//*-----------------------------------------------------------------------
// @mfunc Drop a table
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int RODataSource::Variation_4()
{ 
	BOOL	fResults = TEST_PASS;
	BOOL	fExists;

	if (	!CHECK(m_pITableDefinition->DropTable(&m_pTable->GetTableID()), DB_SEC_E_PERMISSIONDENIED)
		||	!CHECK(m_pTable->DoesTableExist(&m_pTable->GetTableID(), &fExists), S_OK)
		||	!fExists)
		fResults = TEST_FAIL;
	return fResults;
} 
// }} TCW_VAR_PROTOTYPE_END


// {{ TCW_TERMINATE_METHOD
//*-----------------------------------------------------------------------
// @mfunc TestCase Termination Routine 
//
// @rdesc TEST_PASS or TEST_FAIL 
//
BOOL RODataSource::Terminate()
{ 

// {{ TCW_TERM_BASECLASS_CHECK2
	SAFE_RELEASE(m_pITableDefinition);
	m_pITableDefinition		= m_pITableDefinition2;
	m_pITableDefinition2	= NULL;
	SetDBSession(m_pITableDefinition);
	if (m_pTable)
	{
		m_hr = m_pTable->DropTable();
		delete m_pTable;
		m_pTable = NULL;
	}
	return(TCDropColumn::Terminate());
} 	// }}
// }} TCW_TERMINATE_METHOD_END
// }} TCW_TC_PROTOTYPE_END

// Hack to defile CoInitializeEx
WINOLEAPI  CoInitializeEx(LPVOID pvReserved, DWORD dwCoInit);

unsigned WINAPI ThreadProc(LPVOID lpvThreadParam)
{
	CoInitializeEx(NULL, 0);
	TCITableDefinition	*pObject = ((CInParam*)lpvThreadParam)->pObject;
	pObject->MyThreadProc(((CInParam*)lpvThreadParam)->i);
	CoUninitialize();
	return 1;
} //ThreadProc

// {{ TCW_TC_PROTOTYPE(TCAddConstraint_Boundary)
//*-----------------------------------------------------------------------
//| Test Case:		TCAddConstraint_Boundary - General and boundary/null test for ITableDefinitionWithConstraints::AddConstraint
//| Created:  	7/29/99
//*-----------------------------------------------------------------------

//*-----------------------------------------------------------------------
// @mfunc TestCase Initialization Routine
//
// @rdesc TRUE or FALSE
//
BOOL TCAddConstraint_Boundary::Init()
{ 
	// {{ TCW_INIT_BASECLASS_CHECK
	if(TCITableDefinition::Init())
	// }}
	{ 
		if (m_pITDWC == NULL || GetModInfo()->GetClassContext()==CLSCTX_LOCAL_SERVER)
		{
			odtLog << "ITableDefinitionWithConstraints is not supported.\n";
			return TEST_SKIPPED;
		}
		return TRUE;
	} 
	return FALSE;
} 




// {{ TCW_VAR_PROTOTYPE(1)
//*-----------------------------------------------------------------------
// @mfunc Check the session object (QI for interfaces)
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCAddConstraint_Boundary::Variation_1()
{ 
	return DefaultObjectTesting(m_pThisTestModule->m_pIUnknown2, SESSION_INTERFACE);
} 
// }} TCW_VAR_PROTOTYPE_END





// {{ TCW_VAR_PROTOTYPE(2)
//*-----------------------------------------------------------------------
// @mfunc pTableID is NULL => E_INVALIDARG
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCAddConstraint_Boundary::Variation_2()
{ 
	TBEGIN
	CTable				BaseTable(m_pThisTestModule->m_pIUnknown2, (LPWSTR)gwszModuleName);
	DBORDINAL			rgBaseCol[] = {1};
	CForeignKeyCons		consFK;
	CUniqueCons			consUnique;
	CPrimaryKeyCons		consPK;
	CCheckCons			consCheck;

	TESTC_(BaseTable.CreateTable(0, 0), S_OK);
	BaseTable.AddInfoFromColumnsSchemaRowset(m_pITDWC, BaseTable.GetTableName());

	TESTC_(AddUniqueConstraint(&BaseTable, NUMELEM(rgBaseCol), rgBaseCol), S_OK);

	// since base table name has to be inexistent, use reference table name instead
	TESTC_(consFK.SetConstraint(&BaseTable, NUMELEM(rgBaseCol), rgBaseCol, 
		&BaseTable, NUMELEM(rgBaseCol), rgBaseCol, m_SupportedMatchType), S_OK);

	// set up the unique constraint
	TESTC_(consUnique.SetConstraint(&BaseTable, NUMELEM(rgBaseCol), rgBaseCol), S_OK);

	// set up the primary key constraint
	TESTC_(consPK.SetConstraint(&BaseTable, NUMELEM(rgBaseCol), rgBaseCol), S_OK);

	// set up the check constraint
	consCheck.SetConstraintText(L"TRUE != FALSE");

	CHECK(AddConstraintAndCheck(m_pITDWC, NULL, consFK), E_INVALIDARG);
	CHECK(AddConstraintAndCheck(m_pITDWC, NULL, consPK), E_INVALIDARG);
	CHECK(AddConstraintAndCheck(m_pITDWC, NULL, consUnique), E_INVALIDARG);
	CHECK(AddConstraintAndCheck(m_pITDWC, NULL, consCheck), E_INVALIDARG);

CLEANUP:
	BaseTable.DropTable();
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(3)
//*-----------------------------------------------------------------------
// @mfunc *pTableID is DB_NULLID => DB_E_NOTABLE
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCAddConstraint_Boundary::Variation_3()
{ 
	TBEGIN
	CTable				BaseTable(m_pThisTestModule->m_pIUnknown2, (LPWSTR)gwszModuleName);
	DBORDINAL			rgBaseCol[] = {1};
	CForeignKeyCons		consFK;
	CUniqueCons			consUnique;
	CPrimaryKeyCons		consPK;
	CCheckCons			consCheck;
	DBID				TableID;

	DuplicateDBID(DB_NULLID, &TableID);

	TESTC_(BaseTable.CreateTable(0, 0), S_OK);
	BaseTable.AddInfoFromColumnsSchemaRowset(m_pITDWC, BaseTable.GetTableName());
	TESTC_(AddUniqueConstraint(&BaseTable, NUMELEM(rgBaseCol), rgBaseCol), S_OK);

	// since base table name has to be inexistent, use reference table name instead
	TESTC_(consFK.SetConstraint(&BaseTable, NUMELEM(rgBaseCol), rgBaseCol, 
		&BaseTable, NUMELEM(rgBaseCol), rgBaseCol, m_SupportedMatchType), S_OK);

	// set up the unique constraint
	TESTC_(consUnique.SetConstraint(&BaseTable, NUMELEM(rgBaseCol), rgBaseCol), S_OK);

	// set up the primary key constraint
	TESTC_(consPK.SetConstraint(&BaseTable, NUMELEM(rgBaseCol), rgBaseCol), S_OK);

	// set up the check constraint
	CHECK(consCheck.SetLTCheckConstraint(&BaseTable, rgBaseCol[0], 12), S_OK);

	TESTC_(AddConstraintAndCheck(m_pITDWC, &TableID, consFK), DB_E_NOTABLE);
	TESTC_(AddConstraintAndCheck(m_pITDWC, &TableID, consPK), DB_E_NOTABLE);
	TESTC_(AddConstraintAndCheck(m_pITDWC, &TableID, consUnique), DB_E_NOTABLE);
	TESTC_(AddConstraintAndCheck(m_pITDWC, &TableID, consCheck), DB_E_NOTABLE);

CLEANUP:
	BaseTable.DropTable();
	ReleaseDBID(&TableID, FALSE);
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(4)
//*-----------------------------------------------------------------------
// @mfunc Table name is NULL => DB_E_NOTABLE
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCAddConstraint_Boundary::Variation_4()
{ 
	TBEGIN
	CTable				BaseTable(m_pThisTestModule->m_pIUnknown2, (LPWSTR)gwszModuleName);
	DBORDINAL			rgBaseCol[] = {1};
	CForeignKeyCons		consFK;
	CUniqueCons			consUnique;
	CPrimaryKeyCons		consPK;
	CCheckCons			consCheck;
	DBID				TableID;

	TESTC_(BaseTable.CreateTable(0, 0), S_OK);
	BaseTable.AddInfoFromColumnsSchemaRowset(m_pITDWC, BaseTable.GetTableName());
	TESTC_(AddUniqueConstraint(&BaseTable, NUMELEM(rgBaseCol), rgBaseCol), S_OK);

	// since base table name has to be inexistent, use reference table name instead
	TESTC_(consFK.SetConstraint(&BaseTable, NUMELEM(rgBaseCol), rgBaseCol, 
		&BaseTable, NUMELEM(rgBaseCol), rgBaseCol, m_SupportedMatchType), S_OK);

	// set up the unique constraint
	TESTC_(consUnique.SetConstraint(&BaseTable, NUMELEM(rgBaseCol), rgBaseCol), S_OK);

	// set up the primary key constraint
	TESTC_(consPK.SetConstraint(&BaseTable, NUMELEM(rgBaseCol), rgBaseCol), S_OK);

	// set up the check constraint
	CHECK(consCheck.SetLTCheckConstraint(&BaseTable, rgBaseCol[0], 12), S_OK);

	TableID.eKind			= DBKIND_NAME;
	TableID.uName.pwszName	= NULL;

	TESTC_(AddConstraintAndCheck(m_pITDWC, &TableID, consFK), DB_E_NOTABLE);
	TESTC_(AddConstraintAndCheck(m_pITDWC, &TableID, consPK), DB_E_NOTABLE);
	TESTC_(AddConstraintAndCheck(m_pITDWC, &TableID, consUnique), DB_E_NOTABLE);
	TESTC_(AddConstraintAndCheck(m_pITDWC, &TableID, consCheck), DB_E_NOTABLE);

CLEANUP:
	BaseTable.DropTable();
	ReleaseDBID(&TableID, FALSE);
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(5)
//*-----------------------------------------------------------------------
// @mfunc Table name is the empty string => DB_E_NOTABLE
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCAddConstraint_Boundary::Variation_5()
{ 
	TBEGIN
	CTable				BaseTable(m_pThisTestModule->m_pIUnknown2, (LPWSTR)gwszModuleName);
	DBORDINAL			rgBaseCol[] = {1};
	CForeignKeyCons		consFK;
	CUniqueCons			consUnique;
	CPrimaryKeyCons		consPK;
	CCheckCons			consCheck;
	DBID				TableID;

	TESTC_(BaseTable.CreateTable(0, 0), S_OK);
	BaseTable.AddInfoFromColumnsSchemaRowset(m_pITDWC, BaseTable.GetTableName());
	TESTC_(AddUniqueConstraint(&BaseTable, NUMELEM(rgBaseCol), rgBaseCol), S_OK);

	// since base table name has to be inexistent, use reference table name instead
	TESTC_(consFK.SetConstraint(&BaseTable, NUMELEM(rgBaseCol), rgBaseCol, 
		&BaseTable, NUMELEM(rgBaseCol), rgBaseCol, m_SupportedMatchType), S_OK);

	// set up the unique constraint
	TESTC_(consUnique.SetConstraint(&BaseTable, NUMELEM(rgBaseCol), rgBaseCol), S_OK);

	// set up the primary key constraint
	TESTC_(consPK.SetConstraint(&BaseTable, NUMELEM(rgBaseCol), rgBaseCol), S_OK);

	// set up the check constraint
	CHECK(consCheck.SetLTCheckConstraint(&BaseTable, rgBaseCol[0], 17), S_OK);

	TableID.eKind			= DBKIND_NAME;
	TableID.uName.pwszName	= wcsDuplicate(L"");

	TESTC_(AddConstraintAndCheck(m_pITDWC, &TableID, consFK), DB_E_NOTABLE);
	TESTC_(AddConstraintAndCheck(m_pITDWC, &TableID, consPK), DB_E_NOTABLE);
	TESTC_(AddConstraintAndCheck(m_pITDWC, &TableID, consUnique), DB_E_NOTABLE);
	TESTC_(AddConstraintAndCheck(m_pITDWC, &TableID, consCheck), DB_E_NOTABLE);

CLEANUP:
	BaseTable.DropTable();
	ReleaseDBID(&TableID, FALSE);
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(6)
//*-----------------------------------------------------------------------
// @mfunc Table name has maximum length
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCAddConstraint_Boundary::Variation_6()
{ 
	TBEGIN
	CTable				BaseTable(m_pThisTestModule->m_pIUnknown2, (LPWSTR)gwszModuleName);
	CTable				ReferencedTable(m_pITDWC, (LPWSTR)gwszModuleName);
	DBORDINAL			rgBaseCol[] = {1};
	DBORDINAL			rgReferencedCol[] = {1};
	CForeignKeyCons		consFK;
	CUniqueCons			consUnique;
	CPrimaryKeyCons		consPK;
	CCheckCons			consCheck;
	DBID				TableID;

	// create a table with maximum length
	BaseTable.MakeTableName(NULL);
	TableID.eKind			= DBKIND_NAME;
	TableID.uName.pwszName	= BuildValidName(m_cMaxTableName, BaseTable.GetTableName());

	TESTC_(CreateTableWithNoNullableColumns(&BaseTable, 0, 0, TableID.uName.pwszName), S_OK);
	TESTC_(ReferencedTable.CreateTable(0, 0), S_OK);
	ReferencedTable.AddInfoFromColumnsSchemaRowset(m_pITDWC, ReferencedTable.GetTableName());
	TESTC_(AddUniqueConstraint(&ReferencedTable, NUMELEM(rgReferencedCol), rgReferencedCol), S_OK);

	// since base table name has to be inexistent, use reference table name instead
	TESTC_(consFK.SetConstraint(&BaseTable, NUMELEM(rgBaseCol), rgBaseCol, 
		&ReferencedTable, NUMELEM(rgReferencedCol), rgReferencedCol, m_SupportedMatchType), S_OK);

	// set up the unique constraint
	TESTC_(consUnique.SetConstraint(&BaseTable, NUMELEM(rgBaseCol), rgBaseCol), S_OK);

	// set up the primary key constraint
	TESTC_(consPK.SetConstraint(&BaseTable, NUMELEM(rgBaseCol), rgBaseCol), S_OK);

	// set up the check constraint
	CHECK(consCheck.SetLTCheckConstraint(&BaseTable, rgBaseCol[0], 12), S_OK);

	CHECK(AddConstraintAndCheck(m_pITDWC, &TableID, consFK), S_OK);
	CHECK(AddConstraintAndCheck(m_pITDWC, &TableID, consPK), S_OK);
	CHECK(AddConstraintAndCheck(m_pITDWC, &TableID, consUnique), S_OK);
	CHECK(AddConstraintAndCheck(m_pITDWC, &TableID, consCheck), S_OK);

CLEANUP:
	BaseTable.DropTable();
	ReferencedTable.DropTable();
	ReleaseDBID(&TableID, FALSE);
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(7)
//*-----------------------------------------------------------------------
// @mfunc Table name exceeds maximum length => DB_E_NOTABLE
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCAddConstraint_Boundary::Variation_7()
{ 
	TBEGIN
	CTable				BaseTable(m_pThisTestModule->m_pIUnknown2, (LPWSTR)gwszModuleName);
	DBORDINAL			rgBaseCol[] = {1};
	CForeignKeyCons		consFK;
	CUniqueCons			consUnique;
	CPrimaryKeyCons		consPK;
	CCheckCons			consCheck;
	DBID				TableID;

	// create a table with maximum length
	BaseTable.MakeTableName(NULL);
	TableID.eKind			= DBKIND_NAME;
	TableID.uName.pwszName	= BuildValidName(m_cMaxTableName+1, BaseTable.GetTableName());

	TESTC_(CreateTableWithNoNullableColumns(&BaseTable, 0, 0), S_OK);
	TESTC_(AddUniqueConstraint(&BaseTable, NUMELEM(rgBaseCol), rgBaseCol), S_OK);

	// since base table name has to be inexistent, use reference table name instead
	TESTC_(consFK.SetConstraint(&BaseTable, NUMELEM(rgBaseCol), rgBaseCol, 
		&BaseTable, NUMELEM(rgBaseCol), rgBaseCol, m_SupportedMatchType), S_OK);

	// set up the unique constraint
	TESTC_(consUnique.SetConstraint(&BaseTable, NUMELEM(rgBaseCol), rgBaseCol), S_OK);

	// set up the primary key constraint
	TESTC_(consPK.SetConstraint(&BaseTable, NUMELEM(rgBaseCol), rgBaseCol), S_OK);

	// set up the check constraint
	CHECK(consCheck.SetLTCheckConstraint(&BaseTable, rgBaseCol[0], 12), S_OK);

	TESTC_(AddConstraintAndCheck(m_pITDWC, &TableID, consFK), DB_E_NOTABLE);
	TESTC_(AddConstraintAndCheck(m_pITDWC, &TableID, consPK), DB_E_NOTABLE);
	TESTC_(AddConstraintAndCheck(m_pITDWC, &TableID, consUnique), DB_E_NOTABLE);
	TESTC_(AddConstraintAndCheck(m_pITDWC, &TableID, consCheck), DB_E_NOTABLE);

CLEANUP:
	BaseTable.DropTable();
	ReleaseDBID(&TableID, FALSE);
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(8)
//*-----------------------------------------------------------------------
// @mfunc Table name contains illegal characters
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCAddConstraint_Boundary::Variation_8()
{ 
	TBEGIN
	CTable				BaseTable(m_pThisTestModule->m_pIUnknown2, (LPWSTR)gwszModuleName);
	DBORDINAL			rgBaseCol[] = {1};
	CForeignKeyCons		consFK;
	CUniqueCons			consUnique;
	CPrimaryKeyCons		consPK;
	CCheckCons			consCheck;
	DBID				TableID;
	size_t				m, n;

	// create a table with maximum length
	BaseTable.MakeTableName(NULL);
	TableID.eKind			= DBKIND_NAME;
	m = min(m_cMaxTableName, n=5+wcslen(BaseTable.GetTableName()));
	TableID.uName.pwszName	= BuildInvalidName(m, BaseTable.GetTableName(), m_pwszInvalidTableChars);

	TESTC_(CreateTableWithNoNullableColumns(&BaseTable, 0, 0), S_OK);
	TESTC_(AddUniqueConstraint(&BaseTable, NUMELEM(rgBaseCol), rgBaseCol), S_OK);

	// since base table name has to be inexistent, use reference table name instead
	TESTC_(consFK.SetConstraint(&BaseTable, NUMELEM(rgBaseCol), rgBaseCol, 
		&BaseTable, NUMELEM(rgBaseCol), rgBaseCol, m_SupportedMatchType), S_OK);

	// set up the unique constraint
	TESTC_(consUnique.SetConstraint(&BaseTable, NUMELEM(rgBaseCol), rgBaseCol), S_OK);

	// set up the primary key constraint
	TESTC_(consPK.SetConstraint(&BaseTable, NUMELEM(rgBaseCol), rgBaseCol), S_OK);

	// set up the check constraint
	CHECK(consCheck.SetLTCheckConstraint(&BaseTable, rgBaseCol[0], 12), S_OK);

	TESTC_(AddConstraintAndCheck(m_pITDWC, &TableID, consFK), DB_E_NOTABLE);
	TESTC_(AddConstraintAndCheck(m_pITDWC, &TableID, consPK), DB_E_NOTABLE);
	TESTC_(AddConstraintAndCheck(m_pITDWC, &TableID, consUnique), DB_E_NOTABLE);
	TESTC_(AddConstraintAndCheck(m_pITDWC, &TableID, consCheck), DB_E_NOTABLE);

CLEANUP:
	BaseTable.DropTable();
	ReleaseDBID(&TableID, FALSE);
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(9)
//*-----------------------------------------------------------------------
// @mfunc Invalid DBKIND value for the base table
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCAddConstraint_Boundary::Variation_9()
{ 
	TBEGIN
	CTable				BaseTable(m_pThisTestModule->m_pIUnknown2, (LPWSTR)gwszModuleName);
	DBORDINAL			rgBaseCol[] = {1};
	CForeignKeyCons		consFK;
	CUniqueCons			consUnique;
	CPrimaryKeyCons		consPK;
	CCheckCons			consCheck;
	DBID				TableID;

	// create a table with maximum length
	BaseTable.MakeTableName(NULL);
	memset(&TableID, 0, sizeof(DBID));
	TableID.eKind			= 0xce;

	TESTC_(CreateTableWithNoNullableColumns(&BaseTable, 0, 0), S_OK);
	TESTC_(AddUniqueConstraint(&BaseTable, NUMELEM(rgBaseCol), rgBaseCol), S_OK);

	// since base table name has to be inexistent, use reference table name instead
	TESTC_(consFK.SetConstraint(&BaseTable, NUMELEM(rgBaseCol), rgBaseCol, 
		&BaseTable, NUMELEM(rgBaseCol), rgBaseCol, m_SupportedMatchType), S_OK);

	// set up the unique constraint
	TESTC_(consUnique.SetConstraint(&BaseTable, NUMELEM(rgBaseCol), rgBaseCol), S_OK);

	// set up the primary key constraint
	TESTC_(consPK.SetConstraint(&BaseTable, NUMELEM(rgBaseCol), rgBaseCol), S_OK);

	// set up the check constraint
	CHECK(consCheck.SetLTCheckConstraint(&BaseTable, rgBaseCol[0], 12), S_OK);

	TESTC_(AddConstraintAndCheck(m_pITDWC, &TableID, consFK), DB_E_NOTABLE);
	TESTC_(AddConstraintAndCheck(m_pITDWC, &TableID, consPK), DB_E_NOTABLE);
	TESTC_(AddConstraintAndCheck(m_pITDWC, &TableID, consUnique), DB_E_NOTABLE);
	TESTC_(AddConstraintAndCheck(m_pITDWC, &TableID, consCheck), DB_E_NOTABLE);

CLEANUP:
	BaseTable.DropTable();
	ReleaseDBID(&TableID, FALSE);
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(10)
//*-----------------------------------------------------------------------
// @mfunc NULL column list in a constraint, column size is not 0 => E_INVALIDARG
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCAddConstraint_Boundary::Variation_10()
{ 
	TBEGIN
	CTable				BaseTable(m_pThisTestModule->m_pIUnknown2, (LPWSTR)gwszModuleName);
	DBORDINAL			rgBaseCol[] = {1, 2, 3};
	CForeignKeyCons		consFK;
	CUniqueCons			consUnique;
	CPrimaryKeyCons		consPK;
	CCheckCons			consCheck;
	DBCONSTRAINTDESC	*pConsDesc;
	DBID				*p1 = NULL, *p2 = NULL;

	// create a table with maximum length
	TESTC_(CreateTableWithNoNullableColumns(&BaseTable, 0, 0), S_OK);
	TESTC_(AddUniqueConstraint(&BaseTable, NUMELEM(rgBaseCol), rgBaseCol), S_OK);

	// set up the unique constraint
	TESTC_(consUnique.SetConstraint(&BaseTable, NUMELEM(rgBaseCol), rgBaseCol), S_OK);
	pConsDesc = consUnique;
	p1 = pConsDesc->rgColumnList;
	pConsDesc->rgColumnList	= NULL;
	CHECK(AddConstraintAndCheck(m_pITDWC, &BaseTable.GetTableID(), consUnique), E_INVALIDARG);
	pConsDesc->rgColumnList = p1;

	// set up the primary key constraint
	TESTC_(consPK.SetConstraint(&BaseTable, NUMELEM(rgBaseCol), rgBaseCol), S_OK);
	pConsDesc = consPK;
	p1 = pConsDesc->rgColumnList;
	pConsDesc->rgColumnList	= NULL;
	CHECK(AddConstraintAndCheck(m_pITDWC, &BaseTable.GetTableID(), consPK), E_INVALIDARG);
	pConsDesc->rgColumnList = p1;

	// since base table name has to be inexistent, use reference table name instead
	TESTC_(consFK.SetConstraint(&BaseTable, NUMELEM(rgBaseCol), rgBaseCol, 
		&BaseTable, NUMELEM(rgBaseCol), rgBaseCol, m_SupportedMatchType), S_OK);
	pConsDesc = consFK;
	p1 = pConsDesc->rgColumnList;
	pConsDesc->rgColumnList	= NULL;
	CHECK(AddConstraintAndCheck(m_pITDWC, &BaseTable.GetTableID(), consFK), E_INVALIDARG);

	p2 = pConsDesc->rgForeignKeyColumnList;
	pConsDesc->rgForeignKeyColumnList	= NULL;
	TESTC_(AddConstraintAndCheck(m_pITDWC, &BaseTable.GetTableID(), consFK), E_INVALIDARG);

	pConsDesc->rgColumnList = p1;
	CHECK(AddConstraintAndCheck(m_pITDWC, &BaseTable.GetTableID(), consFK), E_INVALIDARG);
	pConsDesc->rgColumnList = p1;
	pConsDesc->rgForeignKeyColumnList = p2;

CLEANUP:
	BaseTable.DropTable();
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(11)
//*-----------------------------------------------------------------------
// @mfunc NULL column name in a constraint
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCAddConstraint_Boundary::Variation_11()
{ 
	TBEGIN
	CTable				BaseTable(m_pThisTestModule->m_pIUnknown2, (LPWSTR)gwszModuleName);
	DBORDINAL			rgBaseCol[] = {1, 2, 3};
	CForeignKeyCons		consFK;
	CUniqueCons			consUnique;
	CPrimaryKeyCons		consPK;
	CCheckCons			consCheck;
	DBCONSTRAINTDESC	*pConsDesc;

	// create a table with maximum length
	TESTC_(CreateTableWithNoNullableColumns(&BaseTable, 0, 0), S_OK);
	TESTC_(AddUniqueConstraint(&BaseTable, NUMELEM(rgBaseCol), rgBaseCol), S_OK);

	// since base table name has to be inexistent, use reference table name instead
	TESTC_(consFK.SetConstraint(&BaseTable, NUMELEM(rgBaseCol), rgBaseCol, 
		&BaseTable, NUMELEM(rgBaseCol), rgBaseCol, m_SupportedMatchType), S_OK);
	pConsDesc = consFK;
	ReleaseDBID(&pConsDesc->rgColumnList[1], FALSE);
	pConsDesc->rgColumnList[1].eKind			= DBKIND_NAME;
	pConsDesc->rgColumnList[1].uName.pwszName	= NULL;
	TESTC_(AddConstraintAndCheck(m_pITDWC, &BaseTable.GetTableID(), consFK), DB_E_NOCOLUMN);

	TESTC_(consFK.SetConstraint(&BaseTable, NUMELEM(rgBaseCol), rgBaseCol, 
		&BaseTable, NUMELEM(rgBaseCol), rgBaseCol, m_SupportedMatchType), S_OK);
	pConsDesc = consFK;
	ReleaseDBID(&pConsDesc->rgColumnList[1], FALSE);
	pConsDesc->rgColumnList[1].eKind			= DBKIND_NAME;
	pConsDesc->rgColumnList[1].uName.pwszName	= NULL;
	ReleaseDBID(&pConsDesc->rgForeignKeyColumnList[2], FALSE);
	pConsDesc->rgForeignKeyColumnList[1].eKind			= DBKIND_NAME;
	pConsDesc->rgForeignKeyColumnList[1].uName.pwszName	= NULL;
	TESTC_(AddConstraintAndCheck(m_pITDWC, &BaseTable.GetTableID(), consFK), DB_E_NOCOLUMN);
	
	TESTC_(consFK.SetConstraint(&BaseTable, NUMELEM(rgBaseCol), rgBaseCol, 
		&BaseTable, NUMELEM(rgBaseCol), rgBaseCol, m_SupportedMatchType), S_OK);
	pConsDesc = consFK;
	ReleaseDBID(&pConsDesc->rgForeignKeyColumnList[1], FALSE);
	pConsDesc->rgForeignKeyColumnList[1].eKind			= DBKIND_NAME;
	pConsDesc->rgForeignKeyColumnList[1].uName.pwszName	= NULL;
	TESTC_(AddConstraintAndCheck(m_pITDWC, &BaseTable.GetTableID(), consFK), DB_E_NOCOLUMN);

	// set up the unique constraint
	TESTC_(consUnique.SetConstraint(&BaseTable, NUMELEM(rgBaseCol), rgBaseCol), S_OK);
	pConsDesc = consUnique;
	ReleaseDBID(&pConsDesc->rgColumnList[1], FALSE);
	pConsDesc->rgColumnList[1].eKind			= DBKIND_NAME;
	pConsDesc->rgColumnList[1].uName.pwszName	= NULL;
	TESTC_(AddConstraintAndCheck(m_pITDWC, &BaseTable.GetTableID(), consUnique), DB_E_NOCOLUMN);

	// set up the primary key constraint
	TESTC_(consPK.SetConstraint(&BaseTable, NUMELEM(rgBaseCol), rgBaseCol), S_OK);
	pConsDesc = consPK;
	ReleaseDBID(&pConsDesc->rgColumnList[1], FALSE);
	pConsDesc->rgColumnList[1].eKind			= DBKIND_NAME;
	pConsDesc->rgColumnList[1].uName.pwszName	= NULL;
	TESTC_(AddConstraintAndCheck(m_pITDWC, &BaseTable.GetTableID(), consPK), DB_E_NOCOLUMN);

CLEANUP:
	BaseTable.DropTable();
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(12)
//*-----------------------------------------------------------------------
// @mfunc Empty string for a column name
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCAddConstraint_Boundary::Variation_12()
{ 
	TBEGIN
	CTable				BaseTable(m_pThisTestModule->m_pIUnknown2, (LPWSTR)gwszModuleName);
	DBORDINAL			rgBaseCol[] = {1, 2, 3};
	CForeignKeyCons		consFK;
	CUniqueCons			consUnique;
	CPrimaryKeyCons		consPK;
	CCheckCons			consCheck;
	DBCONSTRAINTDESC	*pConsDesc;

	// create a table with maximum length
	TESTC_(CreateTableWithNoNullableColumns(&BaseTable, 0, 0), S_OK);
	TESTC_(AddUniqueConstraint(&BaseTable, NUMELEM(rgBaseCol), rgBaseCol), S_OK);

	// since base table name has to be inexistent, use reference table name instead
	TESTC_(consFK.SetConstraint(&BaseTable, NUMELEM(rgBaseCol), rgBaseCol, 
		&BaseTable, NUMELEM(rgBaseCol), rgBaseCol, m_SupportedMatchType), S_OK);
	pConsDesc = consFK;
	ReleaseDBID(&pConsDesc->rgColumnList[1], FALSE);
	pConsDesc->rgColumnList[1].eKind			= DBKIND_NAME;
	pConsDesc->rgColumnList[1].uName.pwszName	= wcsDuplicate(L"");
	CHECK(AddConstraintAndCheck(m_pITDWC, &BaseTable.GetTableID(), consFK), DB_E_NOCOLUMN);

	TESTC_(consFK.SetConstraint(&BaseTable, NUMELEM(rgBaseCol), rgBaseCol, 
		&BaseTable, NUMELEM(rgBaseCol), rgBaseCol, m_SupportedMatchType), S_OK);
	pConsDesc = consFK;
	ReleaseDBID(&pConsDesc->rgColumnList[1], FALSE);
	pConsDesc->rgColumnList[1].eKind			= DBKIND_NAME;
	pConsDesc->rgColumnList[1].uName.pwszName	= wcsDuplicate(L"");
	ReleaseDBID(&pConsDesc->rgForeignKeyColumnList[2], FALSE);
	pConsDesc->rgForeignKeyColumnList[1].eKind			= DBKIND_NAME;
	pConsDesc->rgForeignKeyColumnList[1].uName.pwszName	= wcsDuplicate(L"");
	CHECK(AddConstraintAndCheck(m_pITDWC, &BaseTable.GetTableID(), consFK), DB_E_NOCOLUMN);
	
	TESTC_(consFK.SetConstraint(&BaseTable, NUMELEM(rgBaseCol), rgBaseCol, 
		&BaseTable, NUMELEM(rgBaseCol), rgBaseCol, m_SupportedMatchType), S_OK);
	pConsDesc = consFK;
	ReleaseDBID(&pConsDesc->rgForeignKeyColumnList[1], FALSE);
	pConsDesc->rgForeignKeyColumnList[1].eKind			= DBKIND_NAME;
	pConsDesc->rgForeignKeyColumnList[1].uName.pwszName	= wcsDuplicate(L"");
	CHECK(AddConstraintAndCheck(m_pITDWC, &BaseTable.GetTableID(), consFK), DB_E_NOCOLUMN);

	// set up the unique constraint
	TESTC_(consUnique.SetConstraint(&BaseTable, NUMELEM(rgBaseCol), rgBaseCol), S_OK);
	pConsDesc = consUnique;
	ReleaseDBID(&pConsDesc->rgColumnList[1], FALSE);
	pConsDesc->rgColumnList[1].eKind			= DBKIND_NAME;
	pConsDesc->rgColumnList[1].uName.pwszName	= wcsDuplicate(L"");
	CHECK(AddConstraintAndCheck(m_pITDWC, &BaseTable.GetTableID(), consUnique), DB_E_NOCOLUMN);

	// set up the primary key constraint
	TESTC_(consPK.SetConstraint(&BaseTable, NUMELEM(rgBaseCol), rgBaseCol), S_OK);
	pConsDesc = consPK;
	ReleaseDBID(&pConsDesc->rgColumnList[1], FALSE);
	pConsDesc->rgColumnList[1].eKind			= DBKIND_NAME;
	pConsDesc->rgColumnList[1].uName.pwszName	= wcsDuplicate(L"");
	CHECK(AddConstraintAndCheck(m_pITDWC, &BaseTable.GetTableID(), consPK), DB_E_NOCOLUMN);

CLEANUP:
	BaseTable.DropTable();
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(13)
//*-----------------------------------------------------------------------
// @mfunc Maximum length column name in a constraint
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCAddConstraint_Boundary::Variation_13()
{ 
	TBEGIN
	CTable				BaseTable(m_pITDWC, (LPWSTR)gwszModuleName);
	CTable				ReferencedTable(m_pITDWC, (LPWSTR)gwszModuleName);
	DBORDINAL			rgCol[] = {1};
	CForeignKeyCons		consFK;
	CUniqueCons			consUnique;
	CPrimaryKeyCons		consPK;
	CCheckCons			consCheck;

	WCHAR				*pwszName			= NULL;
	DBCOLUMNDESC		*rgColumnDesc	= NULL;
	DBORDINAL			cColumnDesc		= 0;

	DuplicateColumnDesc(m_rgColumnDesc, m_cColumnDesc, &rgColumnDesc);
	cColumnDesc = m_cColumnDesc;
	ReleaseAllColumnPropSets(rgColumnDesc, cColumnDesc);
	BaseTable.SetColumnDesc(rgColumnDesc, cColumnDesc);
	BaseTable.SetBuildColumnDesc(FALSE);
	BaseTable.MakeTableName(NULL);
	pwszName = wcsDuplicate(BaseTable.GetTableName());

	if (rgColumnDesc[0].dbcid.uName.pwszName)
		SAFE_FREE(rgColumnDesc[0].dbcid.uName.pwszName);
	rgColumnDesc[0].dbcid.eKind = DBKIND_NAME;
	rgColumnDesc[0].dbcid.uName.pwszName = BuildValidName(m_cMaxColName, pwszName);
	SetProperty(&rgColumnDesc[0].rgPropertySets, &rgColumnDesc[0].cPropertySets,
			DBPROP_COL_NULLABLE, 
			VT_BOOL, (LPVOID)VARIANT_FALSE, 
			DBPROPOPTIONS_REQUIRED);
	
	TESTC_(BaseTable.CreateTable(0, 0), S_OK);
	BaseTable.AddInfoFromColumnsSchemaRowset(m_pITDWC, BaseTable.GetTableName());
	TESTC_(ReferencedTable.CreateTable(0, 0), S_OK);
	ReferencedTable.AddInfoFromColumnsSchemaRowset(m_pITDWC, ReferencedTable.GetTableName());
	TESTC_(AddUniqueConstraint(&ReferencedTable, NUMELEM(rgCol), rgCol), S_OK);

	// since base table name has to be inexistent, use reference table name instead
	TESTC_(consFK.SetConstraint(&BaseTable, NUMELEM(rgCol), rgCol, 
		&ReferencedTable, NUMELEM(rgCol), rgCol, m_SupportedMatchType), S_OK);

	// set up the unique constraint
	TESTC_(consUnique.SetConstraint(&BaseTable, NUMELEM(rgCol), rgCol), S_OK);

	// set up the primary key constraint
	TESTC_(consPK.SetConstraint(&BaseTable, NUMELEM(rgCol), rgCol), S_OK);

	// set up the check constraint
	CHECK(consCheck.SetLTCheckConstraint(&BaseTable, rgCol[0], 12), S_OK);

	CHECK(AddConstraintAndCheck(m_pITDWC, &BaseTable.GetTableID(), consFK), S_OK);
	CHECK(AddConstraintAndCheck(m_pITDWC, &BaseTable.GetTableID(), consPK), S_OK);
	CHECK(AddConstraintAndCheck(m_pITDWC, &BaseTable.GetTableID(), consUnique), S_OK);
	CHECK(AddConstraintAndCheck(m_pITDWC, &BaseTable.GetTableID(), consCheck), S_OK);

CLEANUP:
	SAFE_FREE(pwszName);
	CHECK(BaseTable.DropTable(), S_OK);
	CHECK(ReferencedTable.DropTable(), S_OK);
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(14)
//*-----------------------------------------------------------------------
// @mfunc Column name exceeds maximum length
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCAddConstraint_Boundary::Variation_14()
{ 
	TBEGIN
	CTable				BaseTable(m_pITDWC, (LPWSTR)gwszModuleName);
	CTable				ReferencedTable(m_pITDWC, (LPWSTR)gwszModuleName);
	DBORDINAL			rgCol[] = {1};
	CForeignKeyCons		consFK;
	CUniqueCons			consUnique;
	CPrimaryKeyCons		consPK;
	CCheckCons			consCheck;

	WCHAR				*pwszName			= NULL;
	WCHAR				*pwszColName		= NULL;

	DBCOLUMNDESC		*rgColumnDesc	= NULL;
	DBORDINAL			cColumnDesc		= 0;

	DBCONSTRAINTDESC	*pConsDesc;

	DuplicateColumnDesc(m_rgColumnDesc, m_cColumnDesc, &rgColumnDesc);
	cColumnDesc = m_cColumnDesc;
	ReleaseAllColumnPropSets(rgColumnDesc, cColumnDesc);
	BaseTable.SetColumnDesc(rgColumnDesc, cColumnDesc);
	BaseTable.SetBuildColumnDesc(FALSE);
	BaseTable.MakeTableName(NULL);
	pwszName = wcsDuplicate(BaseTable.GetTableName());

	if (rgColumnDesc[0].dbcid.uName.pwszName)
		SAFE_FREE(rgColumnDesc[0].dbcid.uName.pwszName);
	rgColumnDesc[0].dbcid.eKind = DBKIND_NAME;
	rgColumnDesc[0].dbcid.uName.pwszName = BuildValidName(m_cMaxColName, pwszName);
	SetProperty(&rgColumnDesc[0].rgPropertySets, &rgColumnDesc[0].cPropertySets,
			DBPROP_COL_NULLABLE, 
			VT_BOOL, (LPVOID)VARIANT_FALSE, 
			DBPROPOPTIONS_REQUIRED);
	
	TESTC_(BaseTable.CreateTable(0, 0), S_OK);
	BaseTable.AddInfoFromColumnsSchemaRowset(m_pITDWC, BaseTable.GetTableName());
	TESTC_(ReferencedTable.CreateTable(0, 0), S_OK);
	ReferencedTable.AddInfoFromColumnsSchemaRowset(m_pITDWC, ReferencedTable.GetTableName());
	TESTC_(AddUniqueConstraint(&ReferencedTable, NUMELEM(rgCol), rgCol), S_OK);

	pwszColName = BuildValidName(m_cMaxColName+1, pwszName);

	// since base table name has to be inexistent, use reference table name instead
	TESTC_(consFK.SetConstraint(&BaseTable, NUMELEM(rgCol), rgCol, 
		&ReferencedTable, NUMELEM(rgCol), rgCol, m_SupportedMatchType), S_OK);
	pConsDesc = consFK;
	SAFE_FREE(pConsDesc->rgForeignKeyColumnList[0].uName.pwszName);
	pConsDesc->rgForeignKeyColumnList[0].uName.pwszName = wcsDuplicate(pwszColName);

	// set up the unique constraint
	TESTC_(consUnique.SetConstraint(&BaseTable, NUMELEM(rgCol), rgCol), S_OK);
	pConsDesc = consUnique;
	SAFE_FREE(pConsDesc->rgColumnList[0].uName.pwszName);
	pConsDesc->rgColumnList[0].uName.pwszName = wcsDuplicate(pwszColName);

	// set up the primary key constraint
	TESTC_(consPK.SetConstraint(&BaseTable, NUMELEM(rgCol), rgCol), S_OK);
	pConsDesc = consPK;
	SAFE_FREE(pConsDesc->rgColumnList[0].uName.pwszName);
	pConsDesc->rgColumnList[0].uName.pwszName = wcsDuplicate(pwszColName);

	// set up the check constraint
	CHECK(consCheck.SetIsNotNULLCheckConstraint(pwszColName), S_OK);

	CHECK(AddConstraintAndCheck(m_pITDWC, &BaseTable.GetTableID(), consFK), DB_E_NOCOLUMN);
	CHECK(AddConstraintAndCheck(m_pITDWC, &BaseTable.GetTableID(), consPK), DB_E_NOCOLUMN);
	CHECK(AddConstraintAndCheck(m_pITDWC, &BaseTable.GetTableID(), consUnique), DB_E_NOCOLUMN);
	CHECK(AddConstraintAndCheck(m_pITDWC, &BaseTable.GetTableID(), consCheck), E_FAIL);

CLEANUP:
	SAFE_FREE(pwszColName);
	SAFE_FREE(pwszName);
	CHECK(BaseTable.DropTable(), S_OK);
	CHECK(ReferencedTable.DropTable(), S_OK);
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(15)
//*-----------------------------------------------------------------------
// @mfunc Invalid DBKIND for a column DBID of a constraint
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCAddConstraint_Boundary::Variation_15()
{ 
	TBEGIN
	CTable				BaseTable(m_pThisTestModule->m_pIUnknown2, (LPWSTR)gwszModuleName);
	DBORDINAL			rgBaseCol[] = {1, 2, 3};
	CForeignKeyCons		consFK;
	CUniqueCons			consUnique;
	CPrimaryKeyCons		consPK;
	CCheckCons			consCheck;
	DBCONSTRAINTDESC	*pConsDesc;

	// create a table with maximum length
	TESTC_(CreateTableWithNoNullableColumns(&BaseTable, 0, 0), S_OK);
	TESTC_(AddUniqueConstraint(&BaseTable, NUMELEM(rgBaseCol), rgBaseCol), S_OK);

	// since base table name has to be inexistent, use reference table name instead
	TESTC_(consFK.SetConstraint(&BaseTable, NUMELEM(rgBaseCol), rgBaseCol, 
		&BaseTable, NUMELEM(rgBaseCol), rgBaseCol, m_SupportedMatchType), S_OK);
	pConsDesc = consFK;
	ReleaseDBID(&pConsDesc->rgColumnList[1], FALSE);
	pConsDesc->rgColumnList[1].eKind = 0xfe;
	TESTC_(AddConstraintAndCheck(m_pITDWC, &BaseTable.GetTableID(), consFK), DB_E_NOCOLUMN);

	TESTC_(consFK.SetConstraint(&BaseTable, NUMELEM(rgBaseCol), rgBaseCol, 
		&BaseTable, NUMELEM(rgBaseCol), rgBaseCol, m_SupportedMatchType), S_OK);
	pConsDesc = consFK;
	ReleaseDBID(&pConsDesc->rgColumnList[1], FALSE);
	pConsDesc->rgColumnList[1].eKind = 0xfe;
	ReleaseDBID(&pConsDesc->rgForeignKeyColumnList[2], FALSE);
	pConsDesc->rgForeignKeyColumnList[1].eKind = 0xfe;
	TESTC_(AddConstraintAndCheck(m_pITDWC, &BaseTable.GetTableID(), consFK), DB_E_NOCOLUMN);
	
	TESTC_(consFK.SetConstraint(&BaseTable, NUMELEM(rgBaseCol), rgBaseCol, 
		&BaseTable, NUMELEM(rgBaseCol), rgBaseCol, m_SupportedMatchType), S_OK);
	pConsDesc = consFK;
	ReleaseDBID(&pConsDesc->rgForeignKeyColumnList[1], FALSE);
	pConsDesc->rgForeignKeyColumnList[1].eKind = 0xfe;
	TESTC_(AddConstraintAndCheck(m_pITDWC, &BaseTable.GetTableID(), consFK), DB_E_NOCOLUMN);

	// set up the unique constraint
	TESTC_(consUnique.SetConstraint(&BaseTable, NUMELEM(rgBaseCol), rgBaseCol), S_OK);
	pConsDesc = consUnique;
	ReleaseDBID(&pConsDesc->rgColumnList[1], FALSE);
	pConsDesc->rgColumnList[1].eKind = 0xee;
	TESTC_(AddConstraintAndCheck(m_pITDWC, &BaseTable.GetTableID(), consUnique), DB_E_NOCOLUMN);

	// set up the primary key constraint
	TESTC_(consPK.SetConstraint(&BaseTable, NUMELEM(rgBaseCol), rgBaseCol), S_OK);
	pConsDesc = consPK;
	ReleaseDBID(&pConsDesc->rgColumnList[1], FALSE);
	pConsDesc->rgColumnList[1].eKind = 0xac;
	TESTC_(AddConstraintAndCheck(m_pITDWC, &BaseTable.GetTableID(), consPK), DB_E_NOCOLUMN);

CLEANUP:
	BaseTable.DropTable();
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(16)
//*-----------------------------------------------------------------------
// @mfunc Column ID is DB_NULLID
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCAddConstraint_Boundary::Variation_16()
{ 
	TBEGIN
	CTable				BaseTable(m_pThisTestModule->m_pIUnknown2, (LPWSTR)gwszModuleName);
	DBORDINAL			rgBaseCol[] = {1, 2, 3};
	CForeignKeyCons		consFK;
	CUniqueCons			consUnique;
	CPrimaryKeyCons		consPK;
	CCheckCons			consCheck;
	DBCONSTRAINTDESC	*pConsDesc;

	// create a table with maximum length
	TESTC_(CreateTableWithNoNullableColumns(&BaseTable, 0, 0), S_OK);
	TESTC_(AddUniqueConstraint(&BaseTable, NUMELEM(rgBaseCol), rgBaseCol), S_OK);

	// since base table name has to be inexistent, use reference table name instead
	TESTC_(consFK.SetConstraint(&BaseTable, NUMELEM(rgBaseCol), rgBaseCol, 
		&BaseTable, NUMELEM(rgBaseCol), rgBaseCol, m_SupportedMatchType), S_OK);
	pConsDesc = consFK;
	ReleaseDBID(&pConsDesc->rgColumnList[1], FALSE);
	DuplicateDBID(DB_NULLID, &pConsDesc->rgColumnList[1]);
	TESTC_(AddConstraintAndCheck(m_pITDWC, &BaseTable.GetTableID(), consFK), DB_E_NOCOLUMN);

	TESTC_(consFK.SetConstraint(&BaseTable, NUMELEM(rgBaseCol), rgBaseCol, 
		&BaseTable, NUMELEM(rgBaseCol), rgBaseCol, m_SupportedMatchType), S_OK);
	pConsDesc = consFK;
	ReleaseDBID(&pConsDesc->rgColumnList[1], FALSE);
	DuplicateDBID(DB_NULLID, &pConsDesc->rgColumnList[1]);
	ReleaseDBID(&pConsDesc->rgForeignKeyColumnList[2], FALSE);
	DuplicateDBID(DB_NULLID, &pConsDesc->rgForeignKeyColumnList[1]);
	TESTC_(AddConstraintAndCheck(m_pITDWC, &BaseTable.GetTableID(), consFK), DB_E_NOCOLUMN);
	
	TESTC_(consFK.SetConstraint(&BaseTable, NUMELEM(rgBaseCol), rgBaseCol, 
		&BaseTable, NUMELEM(rgBaseCol), rgBaseCol, m_SupportedMatchType), S_OK);
	pConsDesc = consFK;
	ReleaseDBID(&pConsDesc->rgForeignKeyColumnList[1], FALSE);
	DuplicateDBID(DB_NULLID, &pConsDesc->rgForeignKeyColumnList[1]);
	TESTC_(AddConstraintAndCheck(m_pITDWC, &BaseTable.GetTableID(), consFK), DB_E_NOCOLUMN);

	// set up the unique constraint
	TESTC_(consUnique.SetConstraint(&BaseTable, NUMELEM(rgBaseCol), rgBaseCol), S_OK);
	pConsDesc = consUnique;
	ReleaseDBID(&pConsDesc->rgColumnList[1], FALSE);
	memset(&pConsDesc->rgColumnList[1], 0, sizeof(DBID));
	TESTC_(AddConstraintAndCheck(m_pITDWC, &BaseTable.GetTableID(), consUnique), DB_E_NOCOLUMN);

	// set up the primary key constraint
	TESTC_(consPK.SetConstraint(&BaseTable, NUMELEM(rgBaseCol), rgBaseCol), S_OK);
	pConsDesc = consPK;
	ReleaseDBID(&pConsDesc->rgColumnList[1], FALSE);
	memset(&pConsDesc->rgColumnList[1], 0, sizeof(DBID));
	TESTC_(AddConstraintAndCheck(m_pITDWC, &BaseTable.GetTableID(), consPK), DB_E_NOCOLUMN);

CLEANUP:
	BaseTable.DropTable();
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(17)
//*-----------------------------------------------------------------------
// @mfunc NULL pReferencedTableID for a foreign key constraint (with and without cForeignKeyColumns being 0)
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCAddConstraint_Boundary::Variation_17()
{ 
	TBEGIN
	CTable				BaseTable(m_pThisTestModule->m_pIUnknown2, (LPWSTR)gwszModuleName);
	CTable				ReferencedTable(m_pThisTestModule->m_pIUnknown2, (LPWSTR)gwszModuleName);
	DBORDINAL			rgBaseCol[] = {1};
	DBORDINAL			rgReferencedCol[] = {1};
	CForeignKeyCons		consFK;

	// create the referenced table in this catalog
	TESTC_PROVIDER(S_OK == ReferencedTable.CreateTable(0, 0));
	ReferencedTable.AddInfoFromColumnsSchemaRowset(m_pITDWC, ReferencedTable.GetTableName());
	// make the referenced columns unique
	TESTC_(AddUniqueConstraint(&ReferencedTable, rgReferencedCol[0], (DBDEFERRABILITY)0), S_OK);

	TESTC_(BaseTable.CreateTable(0, 0), S_OK);
	BaseTable.AddInfoFromColumnsSchemaRowset(m_pITDWC, BaseTable.GetTableName());
	
	// create the 
	TESTC_(consFK.SetConstraint(&BaseTable, NUMELEM(rgBaseCol), rgBaseCol, 
		&ReferencedTable, NUMELEM(rgReferencedCol), rgReferencedCol, 
		m_SupportedMatchType), S_OK);
	consFK.SetReferencedTableID(NULL);

	CHECK(AddConstraintAndCheck(m_pITDWC, &BaseTable.GetTableID(), consFK), DB_E_BADCONSTRAINTFORM);

	CHECK(consFK.ReleaseForeignKeyColumnList(), S_OK);
	CHECK(AddConstraintAndCheck(m_pITDWC, &BaseTable.GetTableID(), consFK), DB_E_BADCONSTRAINTFORM);

CLEANUP:
	BaseTable.DropTable();
	ReferencedTable.DropTable();
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(18)
//*-----------------------------------------------------------------------
// @mfunc DBNULL_ID *pReferencedTableID for a foreign key constraint
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCAddConstraint_Boundary::Variation_18()
{ 
	TBEGIN
	CTable				BaseTable(m_pThisTestModule->m_pIUnknown2, (LPWSTR)gwszModuleName);
	CTable				ReferencedTable(m_pThisTestModule->m_pIUnknown2, (LPWSTR)gwszModuleName);
	DBORDINAL			rgBaseCol[] = {1};
	DBORDINAL			rgReferencedCol[] = {1};
	CForeignKeyCons		consFK;

	// create the referenced table in this catalog
	TESTC_PROVIDER(S_OK == ReferencedTable.CreateTable(0, 0));
	ReferencedTable.AddInfoFromColumnsSchemaRowset(m_pITDWC, ReferencedTable.GetTableName());
	// make the referenced columns unique
	TESTC_(AddUniqueConstraint(&ReferencedTable, rgReferencedCol[0], (DBDEFERRABILITY)0), S_OK);

	TESTC_(BaseTable.CreateTable(0, 0), S_OK);
	BaseTable.AddInfoFromColumnsSchemaRowset(m_pITDWC, BaseTable.GetTableName());
	
	// create the constraint
	TESTC_(consFK.SetConstraint(&BaseTable, NUMELEM(rgBaseCol), rgBaseCol, 
		&ReferencedTable, NUMELEM(rgReferencedCol), rgReferencedCol, 
		m_SupportedMatchType), S_OK);
	consFK.SetReferencedTableID((DBID*)&DB_NULLID);

	TESTC_(AddConstraintAndCheck(m_pITDWC, &BaseTable.GetTableID(), consFK), DB_E_NOTABLE);

CLEANUP:
	BaseTable.DropTable();
	ReferencedTable.DropTable();
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(19)
//*-----------------------------------------------------------------------
// @mfunc NULL referenced table name for a foreign key constraint
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCAddConstraint_Boundary::Variation_19()
{ 
	TBEGIN
	CTable				BaseTable(m_pThisTestModule->m_pIUnknown2, (LPWSTR)gwszModuleName);
	CTable				ReferencedTable(m_pThisTestModule->m_pIUnknown2, (LPWSTR)gwszModuleName);
	DBORDINAL			rgBaseCol[] = {1};
	DBORDINAL			rgReferencedCol[] = {1};
	CForeignKeyCons		consFK;
	DBID				ReferencedTableID;

	// create the referenced table in this catalog
	TESTC_PROVIDER(S_OK == ReferencedTable.CreateTable(0, 0));
	ReferencedTable.AddInfoFromColumnsSchemaRowset(m_pITDWC, ReferencedTable.GetTableName());
	// make the referenced columns unique
	TESTC_(AddUniqueConstraint(&ReferencedTable, rgReferencedCol[0], (DBDEFERRABILITY)0), S_OK);

	TESTC_(BaseTable.CreateTable(0, 0), S_OK);
	BaseTable.AddInfoFromColumnsSchemaRowset(m_pITDWC, BaseTable.GetTableName());
	
	// create the 
	TESTC_(consFK.SetConstraint(&BaseTable, NUMELEM(rgBaseCol), rgBaseCol, 
		&ReferencedTable, NUMELEM(rgReferencedCol), rgReferencedCol, 
		m_SupportedMatchType), S_OK);
	ReferencedTableID.eKind				= DBKIND_NAME;
	ReferencedTableID.uName.pwszName	= NULL;
	consFK.SetReferencedTableID(&ReferencedTableID);
	TESTC_(AddConstraintAndCheck(m_pITDWC, &BaseTable.GetTableID(), consFK), DB_E_NOTABLE);

CLEANUP:
	BaseTable.DropTable();
	ReferencedTable.DropTable();
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(20)
//*-----------------------------------------------------------------------
// @mfunc Emptry string referenced table name for a foreign key constraint
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCAddConstraint_Boundary::Variation_20()
{ 
	TBEGIN
	CTable				BaseTable(m_pThisTestModule->m_pIUnknown2, (LPWSTR)gwszModuleName);
	CTable				ReferencedTable(m_pThisTestModule->m_pIUnknown2, (LPWSTR)gwszModuleName);
	DBORDINAL			rgBaseCol[] = {1};
	DBORDINAL			rgReferencedCol[] = {1};
	CForeignKeyCons		consFK;
	DBID				ReferencedTableID;

	// create the referenced table in this catalog
	TESTC_PROVIDER(S_OK == ReferencedTable.CreateTable(0, 0));
	ReferencedTable.AddInfoFromColumnsSchemaRowset(m_pITDWC, ReferencedTable.GetTableName());
	// make the referenced columns unique
	TESTC_(AddUniqueConstraint(&ReferencedTable, rgReferencedCol[0], (DBDEFERRABILITY)0), S_OK);

	TESTC_(BaseTable.CreateTable(0, 0), S_OK);
	BaseTable.AddInfoFromColumnsSchemaRowset(m_pITDWC, BaseTable.GetTableName());
	
	// create the constraint
	TESTC_(consFK.SetConstraint(&BaseTable, NUMELEM(rgBaseCol), rgBaseCol, 
		&ReferencedTable, NUMELEM(rgReferencedCol), rgReferencedCol, 
		m_SupportedMatchType), S_OK);
	ReferencedTableID.eKind				= DBKIND_NAME;
	ReferencedTableID.uName.pwszName	= L"";
	consFK.SetReferencedTableID(&ReferencedTableID);
	TESTC_(AddConstraintAndCheck(m_pITDWC, &BaseTable.GetTableID(), consFK), DB_E_NOTABLE);

CLEANUP:
	BaseTable.DropTable();
	ReferencedTable.DropTable();
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(21)
//*-----------------------------------------------------------------------
// @mfunc Maximum length referenced table name for a foreign key constraint
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCAddConstraint_Boundary::Variation_21()
{ 
	TBEGIN
	CTable				BaseTable(m_pThisTestModule->m_pIUnknown2, (LPWSTR)gwszModuleName);
	CTable				ReferencedTable(m_pThisTestModule->m_pIUnknown2, (LPWSTR)gwszModuleName);
	DBORDINAL			rgBaseCol[] = {1};
	DBORDINAL			rgReferencedCol[] = {1};
	CForeignKeyCons		consFK;
	WCHAR				*pwszTableName = NULL;

	// create the referenced table in this catalog
	// create a table with maximum length
	ReferencedTable.MakeTableName(NULL);
	pwszTableName	= BuildValidName(m_cMaxTableName, ReferencedTable.GetTableName());
	TESTC_PROVIDER(S_OK == ReferencedTable.CreateTable(0, 0, pwszTableName));
	ReferencedTable.AddInfoFromColumnsSchemaRowset(m_pITDWC, ReferencedTable.GetTableName());

	// make the referenced columns unique
	TESTC_(AddUniqueConstraint(&ReferencedTable, rgReferencedCol[0], (DBDEFERRABILITY)0), S_OK);

	TESTC_(BaseTable.CreateTable(0, 0), S_OK);
	BaseTable.AddInfoFromColumnsSchemaRowset(m_pITDWC, BaseTable.GetTableName());
	
	// create the 
	TESTC_(consFK.SetConstraint(&BaseTable, NUMELEM(rgBaseCol), rgBaseCol, 
		&ReferencedTable, NUMELEM(rgReferencedCol), rgReferencedCol, 
		m_SupportedMatchType), S_OK);

	TESTC_(AddConstraintAndCheck(m_pITDWC, &BaseTable.GetTableID(), consFK), S_OK);

CLEANUP:
	SAFE_FREE(pwszTableName);
	BaseTable.DropTable();
	ReferencedTable.DropTable();
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(22)
//*-----------------------------------------------------------------------
// @mfunc Referenced table name longer than allowed for a foreign key constraint
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCAddConstraint_Boundary::Variation_22()
{ 
	TBEGIN
	CTable				BaseTable(m_pThisTestModule->m_pIUnknown2, (LPWSTR)gwszModuleName);
	CTable				ReferencedTable(m_pThisTestModule->m_pIUnknown2, (LPWSTR)gwszModuleName);
	DBORDINAL			rgBaseCol[] = {1};
	DBORDINAL			rgReferencedCol[] = {1};
	CForeignKeyCons		consFK;
	WCHAR				*pwszTableName = NULL;
	DBCONSTRAINTDESC	*pConsDesc = consFK;

	// create the referenced table in this catalog
	// create a table with maximum length
	ReferencedTable.MakeTableName(NULL);
	pwszTableName	= BuildValidName(m_cMaxTableName, ReferencedTable.GetTableName());
	TESTC_PROVIDER(S_OK == ReferencedTable.CreateTable(0, 0, pwszTableName));
	ReferencedTable.AddInfoFromColumnsSchemaRowset(m_pITDWC, ReferencedTable.GetTableName());

	// make the referenced columns unique
	TESTC_(AddUniqueConstraint(&ReferencedTable, rgReferencedCol[0], (DBDEFERRABILITY)0), S_OK);

	TESTC_(BaseTable.CreateTable(0, 0), S_OK);
	BaseTable.AddInfoFromColumnsSchemaRowset(m_pITDWC, BaseTable.GetTableName());
	
	// create the 
	TESTC_(consFK.SetConstraint(&BaseTable, NUMELEM(rgBaseCol), rgBaseCol, 
		&ReferencedTable, NUMELEM(rgReferencedCol), rgReferencedCol, 
		m_SupportedMatchType), S_OK);
	SAFE_FREE(pwszTableName);
	ReleaseDBID(pConsDesc->pReferencedTableID, FALSE);
	pConsDesc->pReferencedTableID->eKind = DBKIND_NAME;
	pConsDesc->pReferencedTableID->uName.pwszName = BuildValidName(m_cMaxTableName + 1, ReferencedTable.GetTableName());

	TESTC_(AddConstraintAndCheck(m_pITDWC, &BaseTable.GetTableID(), consFK), DB_E_NOTABLE);

CLEANUP:
	SAFE_FREE(pwszTableName);
	BaseTable.DropTable();
	ReferencedTable.DropTable();
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(23)
//*-----------------------------------------------------------------------
// @mfunc Illegal characters in the referenced table name for a foreign key constraint
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCAddConstraint_Boundary::Variation_23()
{ 
	TBEGIN
	CTable				BaseTable(m_pThisTestModule->m_pIUnknown2, (LPWSTR)gwszModuleName);
	CTable				ReferencedTable(m_pThisTestModule->m_pIUnknown2, (LPWSTR)gwszModuleName);
	DBORDINAL			rgBaseCol[] = {1};
	DBORDINAL			rgReferencedCol[] = {1};
	CForeignKeyCons		consFK;
	DBID				ReferencedTableID;
	size_t				m, n;

	// create the referenced table in this catalog
	// create a table with maximum length
	TESTC_PROVIDER(S_OK == ReferencedTable.CreateTable(0, 0));
	ReferencedTable.AddInfoFromColumnsSchemaRowset(m_pITDWC, ReferencedTable.GetTableName());

	// make the referenced columns unique
	TESTC_(AddUniqueConstraint(&ReferencedTable, rgReferencedCol[0], (DBDEFERRABILITY)0), S_OK);

	TESTC_(BaseTable.CreateTable(0, 0), S_OK);
	BaseTable.AddInfoFromColumnsSchemaRowset(m_pITDWC, BaseTable.GetTableName());
	
	// create the constraint
	TESTC_(consFK.SetConstraint(&BaseTable, NUMELEM(rgBaseCol), rgBaseCol, 
		&ReferencedTable, NUMELEM(rgReferencedCol), rgReferencedCol, 
		m_SupportedMatchType), S_OK);
	m = min(m_cMaxTableName, n=5+wcslen(ReferencedTable.GetTableName()));
	ReferencedTableID.uName.pwszName	= BuildInvalidName(m, ReferencedTable.GetTableName(), m_pwszInvalidTableChars);
	consFK.SetReferencedTableID(&ReferencedTableID);

	TESTC_(AddConstraintAndCheck(m_pITDWC, &BaseTable.GetTableID(), consFK), DB_E_NOTABLE);

CLEANUP:
	BaseTable.DropTable();
	ReferencedTable.DropTable();
	ReleaseDBID(&ReferencedTableID, FALSE);
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(24)
//*-----------------------------------------------------------------------
// @mfunc Bad constraint type
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCAddConstraint_Boundary::Variation_24()
{ 
	TBEGIN
	CTable				BaseTable(m_pThisTestModule->m_pIUnknown2, (LPWSTR)gwszModuleName);
	CConsDesc			cons((DBCONSTRAINTTYPE)0xfd);

	TESTC_(BaseTable.CreateTable(0, 0), S_OK);
	BaseTable.AddInfoFromColumnsSchemaRowset(m_pITDWC, BaseTable.GetTableName());

	CHECK(AddConstraintAndCheck(m_pITDWC, &BaseTable.GetTableID(), cons), DB_E_BADCONSTRAINTTYPE);

CLEANUP:
	BaseTable.DropTable();
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(25)
//*-----------------------------------------------------------------------
// @mfunc Empty list of columns for a unique, primay key or foreign key constraint
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCAddConstraint_Boundary::Variation_25()
{ 
	TBEGIN
	CTable				BaseTable(m_pITDWC, (LPWSTR)gwszModuleName);
	CTable				ReferencedTable(m_pITDWC, (LPWSTR)gwszModuleName);
	DBORDINAL			rgCol[] = {1};
	CForeignKeyCons		consFK;
	CUniqueCons			consUnique;
	CPrimaryKeyCons		consPK;
	CCheckCons			consCheck;
	WCHAR				*pwszConstraintText	= NULL;
	WCHAR				*pwszColValue		= NULL;
	CCol				col;

	TESTC_(ReferencedTable.CreateTable(0, 0), S_OK);
	ReferencedTable.AddInfoFromColumnsSchemaRowset(m_pITDWC, ReferencedTable.GetTableName());
	TESTC_(CreateTableWithNoNullableColumns(&BaseTable, 0, 0), S_OK);
	TESTC_(AddUniqueConstraint(&BaseTable, NUMELEM(rgCol), rgCol), S_OK);

	// since base table name has to be inexistent, use reference table name instead
	TESTC_(consFK.SetConstraint(&BaseTable, NUMELEM(rgCol), rgCol, 
		&ReferencedTable, NUMELEM(rgCol), rgCol, m_SupportedMatchType), S_OK);
	consFK.ReleaseColumnList();
	TEST2C_(AddConstraintAndCheck(m_pITDWC, &BaseTable.GetTableID(), consFK), E_INVALIDARG, DB_E_BADCONSTRAINTFORM);
	
	TESTC_(consFK.SetConstraint(&BaseTable, NUMELEM(rgCol), rgCol, 
		&ReferencedTable, NUMELEM(rgCol), rgCol, m_SupportedMatchType), S_OK);
	consFK.ReleaseForeignKeyColumnList();
	CHECK(AddConstraintAndCheck(m_pITDWC, &BaseTable.GetTableID(), consFK), DB_E_BADCONSTRAINTFORM);

	TESTC_(consFK.SetConstraint(&BaseTable, NUMELEM(rgCol), rgCol, 
		&ReferencedTable, NUMELEM(rgCol), rgCol, m_SupportedMatchType), S_OK);
	consFK.ReleaseForeignKeyColumnList();
	consFK.ReleaseColumnList();
	CHECK(AddConstraintAndCheck(m_pITDWC, &BaseTable.GetTableID(), consFK), DB_E_BADCONSTRAINTFORM);

	// set up the unique constraint
	TESTC_(consUnique.SetConstraint(&BaseTable, NUMELEM(rgCol), rgCol), S_OK);
	consUnique.ReleaseColumnList();
	CHECK(AddConstraintAndCheck(m_pITDWC, &BaseTable.GetTableID(), consUnique), DB_E_BADCONSTRAINTFORM);

	// set up the primary key constraint
	TESTC_(consPK.SetConstraint(&BaseTable, NUMELEM(rgCol), rgCol), S_OK);
	consPK.ReleaseColumnList();
	CHECK(AddConstraintAndCheck(m_pITDWC, &BaseTable.GetTableID(), consPK), DB_E_BADCONSTRAINTFORM);

CLEANUP:
	CHECK(BaseTable.DropTable(), S_OK);
	CHECK(ReferencedTable.DropTable(), S_OK);
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(26)
//*-----------------------------------------------------------------------
// @mfunc Non empty list of columns for a check constraint
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCAddConstraint_Boundary::Variation_26()
{ 
	TBEGIN
	HRESULT				hr;
	CTable				BaseTable(m_pITDWC, (LPWSTR)gwszModuleName);
	CCheckCons			consCheck;
	DBCONSTRAINTDESC	*pcons = consCheck;
	WCHAR				*pwszConstraintText	= NULL;
	WCHAR				*pwszColValue		= NULL;
	CCol				col;
	DBID				rgColList;
	DBID				rgForeignKeyColList;

	TESTC_(BaseTable.CreateTable(0, 0), S_OK);
	BaseTable.AddInfoFromColumnsSchemaRowset(m_pITDWC, BaseTable.GetTableName());

	// set up the check constraint
	CHECK(consCheck.SetLTCheckConstraint(&BaseTable, 1, 12), S_OK);

	DuplicateDBID(*col.GetColID(), &rgColList);
	DuplicateDBID(*col.GetColID(), &rgForeignKeyColList);

	// not empty rgColumnList
	pcons->cColumns = 1;
	pcons->rgColumnList = &rgColList;
	CHECK(AddConstraintAndCheck(m_pITDWC, &BaseTable.GetTableID(), consCheck), DB_E_BADCONSTRAINTFORM);

	// not empty rgForeignKeyColumnList
	pcons->cColumns = 0;
	pcons->rgColumnList = NULL;
	pcons->cForeignKeyColumns = 1;
	pcons->rgForeignKeyColumnList = &rgForeignKeyColList;
	hr = AddConstraintAndCheck(m_pITDWC, &BaseTable.GetTableID(), consCheck);
	// since the number of columns is different from the number of foreign key columns
	// E_INVALIDARG can be returned as well
	if (E_INVALIDARG != hr)
		CHECK(hr, DB_E_BADCONSTRAINTFORM);

	// not empty rgColumnList and rgForeignKeyColumnList
	pcons->cColumns = 1;
	pcons->rgColumnList = &rgColList;
	pcons->cForeignKeyColumns = 1;
	pcons->rgForeignKeyColumnList = &rgForeignKeyColList;
	CHECK(AddConstraintAndCheck(m_pITDWC, &BaseTable.GetTableID(), consCheck), DB_E_BADCONSTRAINTFORM);

CLEANUP:
	pcons->cColumns = 0;
	pcons->rgColumnList = NULL;
	pcons->cForeignKeyColumns = 0;
	pcons->rgForeignKeyColumnList = NULL;
	ReleaseDBID(&rgColList, FALSE);
	ReleaseDBID(&rgForeignKeyColList, FALSE);
	SAFE_FREE(pwszConstraintText);
	SAFE_FREE(pwszColValue);
	BaseTable.DropTable();
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(27)
//*-----------------------------------------------------------------------
// @mfunc Not null pwszConstraintText in a unique, PK or FK constraint
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCAddConstraint_Boundary::Variation_27()
{ 
	TBEGIN
	CTable				BaseTable(m_pITDWC, (LPWSTR)gwszModuleName);
	CTable				ReferencedTable(m_pITDWC, (LPWSTR)gwszModuleName);
	DBORDINAL			rgBaseCol[] = {1};
	DBORDINAL			rgReferencedCol[] = {1};
	CForeignKeyCons		consFK;
	CUniqueCons			consUnique;
	CPrimaryKeyCons		consPK;
	DBCONSTRAINTDESC	*pcons;

	TESTC_(CreateTableWithNoNullableColumns(&BaseTable, 0, 0), S_OK);
	TESTC_(ReferencedTable.CreateTable(0, 0), S_OK);
	TESTC_(AddUniqueConstraint(&ReferencedTable, NUMELEM(rgReferencedCol), rgReferencedCol), S_OK);

	// since base table name has to be inexistent, use reference table name instead
	TESTC_(consFK.SetConstraint(&BaseTable, NUMELEM(rgBaseCol), rgBaseCol, 
		&ReferencedTable, NUMELEM(rgReferencedCol), rgReferencedCol, m_SupportedMatchType), S_OK);
	pcons = consFK;
	pcons->pwszConstraintText = L"fdfd";

	// set up the unique constraint
	TESTC_(consUnique.SetConstraint(&BaseTable, NUMELEM(rgBaseCol), rgBaseCol), S_OK);
	pcons = consUnique;
	pcons->pwszConstraintText = L"fdfd";

	// set up the primary key constraint
	TESTC_(consPK.SetConstraint(&BaseTable, NUMELEM(rgBaseCol), rgBaseCol), S_OK);
	pcons = consPK;
	pcons->pwszConstraintText = L"fdfd";

	CHECK(AddConstraintAndCheck(m_pITDWC, &BaseTable.GetTableID(), consFK), DB_E_BADCONSTRAINTFORM);
	CHECK(AddConstraintAndCheck(m_pITDWC, &BaseTable.GetTableID(), consPK), DB_E_BADCONSTRAINTFORM);
	CHECK(AddConstraintAndCheck(m_pITDWC, &BaseTable.GetTableID(), consUnique), DB_E_BADCONSTRAINTFORM);

CLEANUP:
	pcons = consFK;
	pcons->pwszConstraintText = NULL;
	pcons = consPK;
	pcons->pwszConstraintText = NULL;
	pcons = consUnique;
	pcons->pwszConstraintText = NULL;
	BaseTable.DropTable();
	ReferencedTable.DropTable();
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(28)
//*-----------------------------------------------------------------------
// @mfunc NULL pConstraintDesc => E_INVALIDARG
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCAddConstraint_Boundary::Variation_28()
{ 
	TBEGIN

	CHECK(AddConstraintAndCheck(m_pITDWC, &m_pTable->GetTableID(), NULL), E_INVALIDARG);

	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(29)
//*-----------------------------------------------------------------------
// @mfunc 0 < cColumns and NULL == rgColumnList => E_INVALIDARG
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCAddConstraint_Boundary::Variation_29()
{ 
	TBEGIN
	CTable				BaseTable(m_pThisTestModule->m_pIUnknown2, (LPWSTR)gwszModuleName);
	DBORDINAL			rgBaseCol[] = {1};
	CForeignKeyCons		consFK;
	CUniqueCons			consUnique;
	CPrimaryKeyCons		consPK;
	CCheckCons			consCheck;

	TESTC_(BaseTable.CreateTable(0, 0), S_OK);
	BaseTable.AddInfoFromColumnsSchemaRowset(m_pITDWC, BaseTable.GetTableName());
	TESTC_(AddUniqueConstraint(&BaseTable, NUMELEM(rgBaseCol), rgBaseCol), S_OK);

	// since base table name has to be inexistent, use reference table name instead
	TESTC_(consFK.SetConstraint(&BaseTable, NUMELEM(rgBaseCol), rgBaseCol, 
		&BaseTable, NUMELEM(rgBaseCol), rgBaseCol, m_SupportedMatchType), S_OK);
	CHECK(consFK.ReleaseColumnList(), S_OK);
	((DBCONSTRAINTDESC*)consFK)->cColumns = 3;
	CHECK(AddConstraintAndCheck(m_pITDWC, &BaseTable.GetTableID(), consFK), E_INVALIDARG);
	((DBCONSTRAINTDESC*)consFK)->cColumns = 0;

	// set up the unique constraint
	TESTC_(consUnique.SetConstraint(&BaseTable, NUMELEM(rgBaseCol), rgBaseCol), S_OK);
	CHECK(consUnique.ReleaseColumnList(), S_OK);
	((DBCONSTRAINTDESC*)consUnique)->cColumns = 3;
	CHECK(AddConstraintAndCheck(m_pITDWC, &BaseTable.GetTableID(), consUnique), E_INVALIDARG);
	((DBCONSTRAINTDESC*)consUnique)->cColumns = 0;

	// set up the primary key constraint
	TESTC_(consPK.SetConstraint(&BaseTable, NUMELEM(rgBaseCol), rgBaseCol), S_OK);
	CHECK(consPK.ReleaseColumnList(), S_OK);
	((DBCONSTRAINTDESC*)consPK)->cColumns = 3;
	CHECK(AddConstraintAndCheck(m_pITDWC, &BaseTable.GetTableID(), consPK), E_INVALIDARG);
	((DBCONSTRAINTDESC*)consPK)->cColumns = 0;

	// set up the check constraint
	consCheck.SetConstraintText(L"TRUE != FALSE");
	((DBCONSTRAINTDESC*)consCheck)->cColumns = 3;
	CHECK(AddConstraintAndCheck(m_pITDWC, &BaseTable.GetTableID(), consCheck), E_INVALIDARG);
	((DBCONSTRAINTDESC*)consCheck)->cColumns = 0;

CLEANUP:
	BaseTable.DropTable();
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(30)
//*-----------------------------------------------------------------------
// @mfunc 0 < cForeignKeyColumns and NULL == rgForeignKeyColumnList => E_INVALIDARG
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCAddConstraint_Boundary::Variation_30()
{ 
	TBEGIN
	CTable				BaseTable(m_pThisTestModule->m_pIUnknown2, (LPWSTR)gwszModuleName);
	DBORDINAL			rgBaseCol[] = {1};
	CForeignKeyCons		consFK;
	CUniqueCons			consUnique;
	CPrimaryKeyCons		consPK;
	CCheckCons			consCheck;

	TESTC_(BaseTable.CreateTable(0, 0), S_OK);
	BaseTable.AddInfoFromColumnsSchemaRowset(m_pITDWC, BaseTable.GetTableName());
	TESTC_(AddUniqueConstraint(&BaseTable, NUMELEM(rgBaseCol), rgBaseCol), S_OK);

	// since base table name has to be inexistent, use reference table name instead
	TESTC_(consFK.SetConstraint(&BaseTable, NUMELEM(rgBaseCol), rgBaseCol, 
		&BaseTable, NUMELEM(rgBaseCol), rgBaseCol, m_SupportedMatchType), S_OK);
	CHECK(consFK.ReleaseForeignKeyColumnList(), S_OK);
	((DBCONSTRAINTDESC*)consFK)->cForeignKeyColumns = 3;
	CHECK(AddConstraintAndCheck(m_pITDWC, &BaseTable.GetTableID(), consFK), E_INVALIDARG);
	((DBCONSTRAINTDESC*)consFK)->cForeignKeyColumns = 0;

	// set up the unique constraint
	TESTC_(consUnique.SetConstraint(&BaseTable, NUMELEM(rgBaseCol), rgBaseCol), S_OK);
	((DBCONSTRAINTDESC*)consUnique)->cForeignKeyColumns = 3;
	CHECK(AddConstraintAndCheck(m_pITDWC, &BaseTable.GetTableID(), consUnique), E_INVALIDARG);
	((DBCONSTRAINTDESC*)consUnique)->cForeignKeyColumns = 0;

	// set up the primary key constraint
	TESTC_(consPK.SetConstraint(&BaseTable, NUMELEM(rgBaseCol), rgBaseCol), S_OK);
	((DBCONSTRAINTDESC*)consPK)->cForeignKeyColumns = 3;
	CHECK(AddConstraintAndCheck(m_pITDWC, &BaseTable.GetTableID(), consPK), E_INVALIDARG);
	((DBCONSTRAINTDESC*)consPK)->cForeignKeyColumns = 0;

	// set up the check constraint
	consCheck.SetConstraintText(L"TRUE != FALSE");
	((DBCONSTRAINTDESC*)consCheck)->cForeignKeyColumns = 3;
	CHECK(AddConstraintAndCheck(m_pITDWC, &BaseTable.GetTableID(), consCheck), E_INVALIDARG);
	((DBCONSTRAINTDESC*)consCheck)->cForeignKeyColumns = 0;

CLEANUP:
	BaseTable.DropTable();
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(31)
//*-----------------------------------------------------------------------
// @mfunc Constraint is not foreign key and pReferencedTableID is not NULL
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCAddConstraint_Boundary::Variation_31()
{ 
	TBEGIN
	CTable				BaseTable(m_pThisTestModule->m_pIUnknown2, (LPWSTR)gwszModuleName);
	DBORDINAL			rgBaseCol[] = {1};
	CForeignKeyCons		consFK;
	CUniqueCons			consUnique;
	CPrimaryKeyCons		consPK;
	CCheckCons			consCheck;
	DBID				ReferencedTableID;
	WCHAR				*pwszConstraintText	= NULL;
	WCHAR				*pwszColValue		= NULL;
	CCol				col;
	ReferencedTableID.eKind				= DBKIND_NAME;
	ReferencedTableID.uName.pwszName	= (LPWSTR)0x01234567;
	
	TESTC_(CreateTableWithNoNullableColumns(&BaseTable, 0, 0), S_OK);

	// set up the unique constraint
	TESTC_(consUnique.SetConstraint(&BaseTable, NUMELEM(rgBaseCol), rgBaseCol), S_OK);
	((DBCONSTRAINTDESC*)consUnique)->pReferencedTableID = &ReferencedTableID;
	CHECK(AddConstraintAndCheck(m_pITDWC, &BaseTable.GetTableID(), consUnique), DB_E_BADCONSTRAINTFORM);
	((DBCONSTRAINTDESC*)consUnique)->pReferencedTableID = NULL;

	// set up the primary key constraint
	TESTC_(consPK.SetConstraint(&BaseTable, NUMELEM(rgBaseCol), rgBaseCol), S_OK);
	((DBCONSTRAINTDESC*)consPK)->pReferencedTableID = &ReferencedTableID;
	CHECK(AddConstraintAndCheck(m_pITDWC, &BaseTable.GetTableID(), consPK), DB_E_BADCONSTRAINTFORM);
	((DBCONSTRAINTDESC*)consPK)->pReferencedTableID = NULL;

	// set up the check constraint
	TESTC_(BaseTable.GetColInfo(rgBaseCol[0], col), S_OK);
	TESTC_(BaseTable.GetLiteralAndValue(col, &pwszColValue, rand(), col.GetColNum(), PRIMARY), S_OK);
	SAFE_FREE(pwszConstraintText);
	SAFE_ALLOC(pwszConstraintText, WCHAR, 1 + wcslen(col.GetColName()) + wcslen(pwszColValue) + 3);
	wcscpy(pwszConstraintText, col.GetColName());
	wcscat(pwszConstraintText, L" < ");
	wcscat(pwszConstraintText, pwszColValue);
	consCheck.SetConstraintText(pwszConstraintText);

	((DBCONSTRAINTDESC*)consCheck)->pReferencedTableID = &ReferencedTableID;
	CHECK(AddConstraintAndCheck(m_pITDWC, &BaseTable.GetTableID(), consCheck), DB_E_BADCONSTRAINTFORM);
	((DBCONSTRAINTDESC*)consCheck)->pReferencedTableID = NULL;

CLEANUP:
	SAFE_FREE(pwszConstraintText);
	SAFE_FREE(pwszColValue);
	BaseTable.DropTable();
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(32)
//*-----------------------------------------------------------------------
// @mfunc Non empty list of foreign keys for a constraint that is not foreign key
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCAddConstraint_Boundary::Variation_32()
{ 
	TBEGIN
	HRESULT				hr;
	CTable				BaseTable(m_pThisTestModule->m_pIUnknown2, (LPWSTR)gwszModuleName);
	CForeignKeyCons		consFK;
	CUniqueCons			consUnique;
	CPrimaryKeyCons		consPK;
	CCheckCons			consCheck;
	const DBORDINAL		cColumns	= 2;
	DBID				rgColumnList[cColumns];
	DBORDINAL			rgBaseCol[cColumns] = {1, 2};

	rgColumnList[0].eKind				= DBKIND_NAME;
	rgColumnList[0].uName.pwszName	= (LPWSTR)0x01234567;
	rgColumnList[1].eKind				= 0xfe;
	rgColumnList[1].uName.pwszName	= (LPWSTR)0x01234567;
	
	TESTC_(BaseTable.CreateTable(0, 0), S_OK);
	BaseTable.AddInfoFromColumnsSchemaRowset(m_pITDWC, BaseTable.GetTableName());

	// set up the unique constraint
	TESTC_(consUnique.SetConstraint(&BaseTable, NUMELEM(rgBaseCol), rgBaseCol), S_OK);
	((DBCONSTRAINTDESC*)consUnique)->cForeignKeyColumns = cColumns;
	((DBCONSTRAINTDESC*)consUnique)->rgForeignKeyColumnList = rgColumnList;
	hr = AddConstraintAndCheck(m_pITDWC, &BaseTable.GetTableID(), consUnique);
	CHECK(hr, DB_E_BADCONSTRAINTFORM);
	((DBCONSTRAINTDESC*)consUnique)->cForeignKeyColumns = 0;
	((DBCONSTRAINTDESC*)consUnique)->rgForeignKeyColumnList = NULL;

	// set up the primary key constraint
	TESTC_(consPK.SetConstraint(&BaseTable, NUMELEM(rgBaseCol), rgBaseCol), S_OK);
	((DBCONSTRAINTDESC*)consPK)->cForeignKeyColumns = cColumns;
	((DBCONSTRAINTDESC*)consPK)->rgForeignKeyColumnList = rgColumnList;
	hr = AddConstraintAndCheck(m_pITDWC, &BaseTable.GetTableID(), consPK);
	CHECK(hr, DB_E_BADCONSTRAINTFORM);
	((DBCONSTRAINTDESC*)consPK)->cForeignKeyColumns = 0;
	((DBCONSTRAINTDESC*)consPK)->rgForeignKeyColumnList = NULL;

	// set up the check constraint
	consCheck.SetConstraintText(L"TRUE != FALSE");
	((DBCONSTRAINTDESC*)consCheck)->cForeignKeyColumns = cColumns;
	((DBCONSTRAINTDESC*)consCheck)->rgForeignKeyColumnList = rgColumnList;
	hr = AddConstraintAndCheck(m_pITDWC, &BaseTable.GetTableID(), consCheck);
	if (E_INVALIDARG != hr)
		CHECK(hr, DB_E_BADCONSTRAINTFORM);
	((DBCONSTRAINTDESC*)consCheck)->cForeignKeyColumns = 0;
	((DBCONSTRAINTDESC*)consCheck)->rgForeignKeyColumnList = NULL;

CLEANUP:
	BaseTable.DropTable();
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(33)
//*-----------------------------------------------------------------------
// @mfunc Inexistent referenced table
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCAddConstraint_Boundary::Variation_33()
{ 
	TBEGIN
	CTable					BaseTable(m_pITDWC, (LPWSTR)gwszModuleName);
	CTable					Table(m_pITDWC, (LPWSTR)gwszModuleName);
	CForeignKeyCons			cons;
	DBORDINAL				rgBaseCol[]			= {1};
	DBORDINAL				rgReferencedCol[]	= {1};

	// create a table
	TESTC_(BaseTable.CreateTable(0, 0), S_OK);
	BaseTable.AddInfoFromColumnsSchemaRowset(m_pITDWC, BaseTable.GetTableName());
	
	// select a column
	TESTC_(cons.SetConstraint(&BaseTable, NUMELEM(rgBaseCol), rgBaseCol,
		&BaseTable, NUMELEM(rgReferencedCol), rgReferencedCol, m_SupportedMatchType), S_OK);

	// set referenced table to an inexistent table name
	Table.MakeTableName(NULL);
	cons.SetReferencedTableID(&Table.GetTableID());

	// add the foreign key constraint
	TESTC_(AddConstraintAndCheck(m_pITDWC, &BaseTable.GetTableID(), cons), DB_E_NOTABLE);

CLEANUP:
	BaseTable.DropTable();
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END





// {{ TCW_VAR_PROTOTYPE(34)
//*-----------------------------------------------------------------------
// @mfunc Add several constraints to the table
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCAddConstraint_Boundary::Variation_34()
{ 
	TBEGIN
	CTable				ReferencedTable(m_pThisTestModule->m_pIUnknown2, (LPWSTR)gwszModuleName);
	CTable				BaseTable(m_pThisTestModule->m_pIUnknown2, (LPWSTR)gwszModuleName);
	CUniqueCons			consUnique;
	CPrimaryKeyCons		consPrimaryKey;
	CForeignKeyCons		consForeignKey(NULL, m_SupportedMatchType);
	CCheckCons			consCheck;
	DBORDINAL			rgReferencedCol[] = {1};
	DBORDINAL			rgCols[] = {1};
	CCol				col;

	// create support for foreign key constraint
	TESTC_(ReferencedTable.CreateTable(0, 0), S_OK);
	ReferencedTable.AddInfoFromColumnsSchemaRowset(m_pITableDefinition, 
		ReferencedTable.GetTableID().eKind? ReferencedTable.GetTableID().uName.pwszName: NULL);
	// make the referenced columns unique
	TESTC_(AddUniqueConstraint(&ReferencedTable, rgReferencedCol[0], (DBDEFERRABILITY)0), S_OK);

	TESTC_(CreateTableWithNoNullableColumns(&BaseTable, 0, 0), S_OK);
	BaseTable.AddInfoFromColumnsSchemaRowset(m_pITableDefinition, 
		BaseTable.GetTableID().eKind? BaseTable.GetTableID().uName.pwszName: NULL);

	// set a unique constraint on the second column
	CHECK(consUnique.SetConstraint(&BaseTable, 1, rgCols), S_OK);
	CHECK(AddConstraintAndCheck(m_pITDWC, &BaseTable.GetTableID(), consUnique), S_OK);

	// set a primary key on the first column of the table
	CHECK(consPrimaryKey.SetConstraint(&BaseTable, 1, rgCols), S_OK);
	CHECK(AddConstraintAndCheck(m_pITDWC, &BaseTable.GetTableID(), consPrimaryKey), S_OK);

	// set a simple foreign key constraint
	TESTC_(ReferencedTable.GetColInfo(1, col), S_OK);
	consForeignKey.AddColumn(col.GetColID());
	TESTC_(BaseTable.GetColInfo(1, col), S_OK);
	consForeignKey.AddForeignKeyColumn(col.GetColID());
	consForeignKey.SetReferencedTableID(&ReferencedTable.GetTableID());
	CHECK(AddConstraintAndCheck(m_pITDWC, &BaseTable.GetTableID(), consForeignKey), S_OK);
	
	TESTC_(consCheck.SetLTCheckConstraint(&BaseTable, 2, 3), S_OK);
	CHECK(AddConstraintAndCheck(m_pITDWC, &BaseTable.GetTableID(), consCheck), S_OK);

CLEANUP:
	CHECK(BaseTable.DropTable(), S_OK);
	CHECK(ReferencedTable.DropTable(), S_OK);
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(35)
//*-----------------------------------------------------------------------
// @mfunc Inexistent table name => DB_E_NOTABLE
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCAddConstraint_Boundary::Variation_35()
{ 
	TBEGIN
	CTable				ReferencedTable(m_pITDWC, (LPWSTR)gwszModuleName);
	DBORDINAL			rgCol[] = {1};
	CForeignKeyCons		consFK(NULL, m_SupportedMatchType);
	CUniqueCons			consUnique;
	CPrimaryKeyCons		consPK;
	CCheckCons			consCheck;

	CCol				col;

	DBID				dbidInexistent;

	dbidInexistent.eKind = DBKIND_NAME;
	dbidInexistent.uName.pwszName = L"Inexistent";

	TESTC_(ReferencedTable.CreateTable(0, 0), S_OK);
	ReferencedTable.AddInfoFromColumnsSchemaRowset(m_pITDWC, ReferencedTable.GetTableName());
	TESTC_(AddUniqueConstraint(&ReferencedTable, NUMELEM(rgCol), rgCol), S_OK);
	TESTC_(ReferencedTable.GetColInfo(rgCol[0], col), S_OK);

	// since base table name has to be inexistent, use reference table name instead
	consFK.SetReferencedTableID(&ReferencedTable.GetTableID());
	consFK.AddColumn(col.GetColID());
	consFK.AddForeignKeyColumn(col.GetColID());

	// set up the unique constraint
	consUnique.AddColumn(col.GetColID());

	// set up the primary key constraint
	consPK.AddColumn(col.GetColID());

	// set up the check constraint
	CHECK(consCheck.SetIsNotNULLCheckConstraint(col.GetColID()->uName.pwszName), S_OK);

	CHECK(AddConstraintAndCheck(m_pITDWC, &dbidInexistent, consFK), DB_E_NOTABLE);
	CHECK(AddConstraintAndCheck(m_pITDWC, &dbidInexistent, consPK), DB_E_NOTABLE);
	CHECK(AddConstraintAndCheck(m_pITDWC, &dbidInexistent, consUnique), DB_E_NOTABLE);
	CHECK(AddConstraintAndCheck(m_pITDWC, &dbidInexistent, consCheck), DB_E_NOTABLE);

CLEANUP:
	CHECK(ReferencedTable.DropTable(), S_OK);
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(36)
//*-----------------------------------------------------------------------
// @mfunc Inexistent column name => DB_E_NOCOLUMN
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCAddConstraint_Boundary::Variation_36()
{ 
	TBEGIN
	CTable				BaseTable(m_pITDWC, (LPWSTR)gwszModuleName);
	CTable				ReferencedTable(m_pITDWC, (LPWSTR)gwszModuleName);
	DBORDINAL			rgCol[] = {1};
	CForeignKeyCons		consFK;
	CUniqueCons			consUnique;
	CPrimaryKeyCons		consPK;
	CCheckCons			consCheck;

	DBCOLUMNDESC		*rgColumnDesc	= NULL;
	DBORDINAL			cColumnDesc		= 0;

	DBID				dbidInexistent;

	dbidInexistent.eKind = DBKIND_NAME;
	dbidInexistent.uName.pwszName = L"Inexistent";

	DuplicateColumnDesc(m_rgColumnDesc, m_cColumnDesc, &rgColumnDesc);
	cColumnDesc = m_cColumnDesc;
	ReleaseAllColumnPropSets(rgColumnDesc, cColumnDesc);
	BaseTable.SetColumnDesc(rgColumnDesc, cColumnDesc);
	BaseTable.SetBuildColumnDesc(FALSE);

	SetProperty(&rgColumnDesc[0].rgPropertySets, &rgColumnDesc[0].cPropertySets,
			DBPROP_COL_NULLABLE, 
			VT_BOOL, (LPVOID)VARIANT_FALSE, 
			DBPROPOPTIONS_REQUIRED);
	
	TESTC_(BaseTable.CreateTable(0, 0), S_OK);
	BaseTable.AddInfoFromColumnsSchemaRowset(m_pITDWC, BaseTable.GetTableName());
	TESTC_(ReferencedTable.CreateTable(0, 0), S_OK);
	ReferencedTable.AddInfoFromColumnsSchemaRowset(m_pITDWC, ReferencedTable.GetTableName());
	TESTC_(AddUniqueConstraint(&ReferencedTable, NUMELEM(rgCol), rgCol), S_OK);

	// since base table name has to be inexistent, use reference table name instead
	TESTC_(consFK.SetConstraint(&BaseTable, 0, NULL,
		&ReferencedTable, NUMELEM(rgCol), rgCol, m_SupportedMatchType), S_OK);
	consFK.AddForeignKeyColumn(&dbidInexistent);

	// set up the unique constraint
	consUnique.AddColumn(&dbidInexistent);

	// set up the primary key constraint
	consPK.AddColumn(&dbidInexistent);

	// set up the check constraint
	CHECK(consCheck.SetIsNotNULLCheckConstraint(dbidInexistent.uName.pwszName), S_OK);

	CHECK(AddConstraintAndCheck(m_pITDWC, &BaseTable.GetTableID(), consFK), DB_E_NOCOLUMN);
	CHECK(AddConstraintAndCheck(m_pITDWC, &BaseTable.GetTableID(), consPK), DB_E_NOCOLUMN);
	CHECK(AddConstraintAndCheck(m_pITDWC, &BaseTable.GetTableID(), consUnique), DB_E_NOCOLUMN);
	CHECK(AddConstraintAndCheck(m_pITDWC, &BaseTable.GetTableID(), consCheck), DB_E_NOCOLUMN);

CLEANUP:
	CHECK(BaseTable.DropTable(), S_OK);
	CHECK(ReferencedTable.DropTable(), S_OK);
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END


// {{ TCW_TERMINATE_METHOD
//*-----------------------------------------------------------------------
// @mfunc TestCase Termination Routine 
//
// @rdesc TEST_PASS or TEST_FAIL 
//
BOOL TCAddConstraint_Boundary::Terminate()
{ 
	// TO DO:  Add your own code here 

// {{ TCW_TERM_BASECLASS_CHECK2
	return(TCITableDefinition::Terminate());
} 	// }}
// }} TCW_TERMINATE_METHOD_END
// }} TCW_TC_PROTOTYPE_END


// {{ TCW_TC_PROTOTYPE(TCAddConstraint_UNIQUE)
//*-----------------------------------------------------------------------
//| Test Case:		TCAddConstraint_UNIQUE - Testcase for ITableDefinitionWithConstraints::AddConstraint used with DBCONSTRAINTTYPE_UNIQUE
//| Created:  	7/29/99
//*-----------------------------------------------------------------------

//*-----------------------------------------------------------------------
// @mfunc TestCase Initialization Routine
//
// @rdesc TRUE or FALSE
//
BOOL TCAddConstraint_UNIQUE::Init()
{ 
	// {{ TCW_INIT_BASECLASS_CHECK
	if(TCITableDefinition::Init())
	// }}
	{ 
		if (m_pITDWC == NULL)
		{
			odtLog << "ITableDefinitionWithConstraints is not supported.\n";
			return TEST_SKIPPED;
		}
		return TRUE;
	} 
	return FALSE;
} 




// {{ TCW_VAR_PROTOTYPE(1)
//*-----------------------------------------------------------------------
// @mfunc Create a table and try to apply the constraint on each column
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCAddConstraint_UNIQUE::Variation_1()
{ 
	TBEGIN

	CTable				Table(m_pThisTestModule->m_pIUnknown2, (LPWSTR)gwszModuleName);
	DBORDINAL			index;
	CUniqueCons			cons;
	DBORDINAL			cColCount		=	0,
						cTotalLength	=	0,
						start			=	1,
						cColsInTable	=	0;
	HRESULT				hrExpected;
	ULONG				ulNumberOfTests	=	0;

	// create the base table
	TESTC_(Table.CreateTable(0, 0), S_OK);
	Table.AddInfoFromColumnsSchemaRowset(m_pITDWC, Table.GetTableName());

	// build the constraint

	// try to set all the columns in the unique keyunique
	// Step 1: Skip BLOBs and Variable length columns
	// and set Unique constraint on fixed length columns.
	// It should succeed.
	cColsInTable	=	Table.CountColumnsOnTable();

	while(start < cColsInTable) {

		cons.ReleaseColumnList();
		cTotalLength	=	0;
		hrExpected		=	S_OK;

		for (index = start, cColCount = 0; index <= Table.CountColumnsOnTable() &&
			cColCount < cMaxColsPerCons; index++)
		{
			CCol	col;
			DBORDINAL	colSizeInBytes = 0; //how many bytes the column contributes into maximum size of constraint

			TESTC_(Table.GetColInfo(index, col), S_OK);

			// Note: col.GetColumnSize returns length for string data types and we need size in bytes
			//			so multiply ColumnSize by 2 for WSTR
			if(col.GetIsFixedLength() )
				colSizeInBytes = col.GetColumnSize() * (col.GetProviderType()==DBTYPE_WSTR ? 2:1);
			else
				colSizeInBytes = 0;

			if (col.GetIsLong() ||
					cTotalLength + colSizeInBytes > cMaxColLengthPerCons)
				continue;

			cTotalLength += colSizeInBytes;
			cons.AddColumn(col.GetColID());
			cColCount++;
		}

		if (cColCount)
		{
			ulNumberOfTests++;
			
			TESTC_(AddConstraintAndCheck(m_pITDWC, &Table.GetTableID(), cons), hrExpected);
			if (hrExpected == S_OK) {
				TESTC_(DropConstraintAndCheck(m_pITDWC, &Table.GetTableID(), cons), S_OK);
			}
		}

		start = index;
	}
	TESTC(ulNumberOfTests>0);

CLEANUP:
	Table.DropTable();
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END





// {{ TCW_VAR_PROTOTYPE(2)
//*-----------------------------------------------------------------------
// @mfunc Set a unique constraint on each type of column
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCAddConstraint_UNIQUE::Variation_2()
{ 
	TBEGIN
	DBORDINAL			index;
	CTable				Table(m_pThisTestModule->m_pIUnknown2, (LPWSTR)gwszModuleName);
	CUniqueCons			cons;
	DBCOLUMNDESC		*rgNewColumnDesc	= NULL;
	DBID				*pTableID			= NULL;
	HRESULT				hrExpected			= S_OK;

	// create a new table with a NOT NULLABLE column
	TESTC_(Table.CreateTable(0, 0), S_OK);
	Table.AddInfoFromColumnsSchemaRowset(m_pITDWC, Table.GetTableName());
	Table.BuildColumnDescs(&rgNewColumnDesc);

	for (index=1; index <= Table.CountColumnsOnTable(); index++)
	{
		CCol	col;

		TESTC_(Table.GetColInfo(index, col), S_OK);

		cons.ReleaseColumnList();
		cons.AddColumn(col.GetColID());

		// Note: col.GetColumnSize returns length for string data types and we need size in bytes
		//			so multiply ColumnSize by 2 for WSTR
		if (col.GetIsLong() ||
			(col.GetIsFixedLength() && (col.GetColumnSize() * (col.GetProviderType()==DBTYPE_WSTR ? 2:1) > cMaxColLengthPerCons)))
			hrExpected = E_FAIL;
		else
			hrExpected = S_OK;


		odtLog << col.GetProviderTypeName() << "\t -> Expected: " << (hrExpected==S_OK ? "S_OK" : "E_FAIL") << "\n";

		CHECK(AddConstraintAndCheck(m_pITDWC, &Table.GetTableID(), cons), hrExpected);
		if (hrExpected == S_OK) {
			CHECK(DropConstraintAndCheck(m_pITDWC, &Table.GetTableID(), cons), S_OK);
		}

		CHECK(CreateAndCheckTableWithConstraints(m_pITDWC, NULL, NULL,
			m_cColumnDesc, rgNewColumnDesc, 1, cons, IID_IRowset, 0, NULL,
			&pTableID, NULL), hrExpected);
		if (hrExpected == S_OK) {
			CHECK(DropTableAndCheck(pTableID, m_pITDWC), S_OK);
			ReleaseDBID(pTableID, TRUE);
		}
	}

CLEANUP:
	ReleaseColumnDesc(rgNewColumnDesc, m_cColumnDesc, TRUE);
	Table.DropTable();
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(3)
//*-----------------------------------------------------------------------
// @mfunc Create a unique constraint that uses several columns
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCAddConstraint_UNIQUE::Variation_3()
{ 
	TBEGIN
	CTable				Table(m_pThisTestModule->m_pIUnknown2, (LPWSTR)gwszModuleName);
	DBORDINAL			index;
	DBORDINAL			indxCol;
	CUniqueCons			cons;
	DBORDINAL			cCols;
	DBCOLUMNDESC		*rgNewColumnDesc	= NULL;
	DBID				*pTableID = NULL;
	DBORDINAL			cTotalLength = 0;

	// create a new table with a NOT NULLABLE column
	TESTC_(Table.CreateTable(0, 0), S_OK);
	Table.AddInfoFromColumnsSchemaRowset(m_pITDWC, Table.GetTableName());
	Table.BuildColumnDescs(&rgNewColumnDesc);

	cCols = 2 + rand() % __min(20, (Table.CountColumnsOnTable()-1));

	for (index=0, indxCol=1; index < cCols && indxCol <= Table.CountColumnsOnTable(); indxCol++)
	{
		CCol	col;
		DBORDINAL	colSizeInBytes = 0; //how many bytes the column contributes into maximum size of constraint
		//make sure we have at least 2 columns before randomizing the rest
		if ( cons.cColumns() < 2 || rand() % 2)
		{
			TESTC_(Table.GetColInfo(indxCol, col), S_OK);

			// Note: col.GetColumnSize returns length for string data types and we need size in bytes
			//			so multiply ColumnSize by 2 for WSTR
			if(col.GetIsFixedLength() )
				colSizeInBytes = col.GetColumnSize() * (col.GetProviderType()==DBTYPE_WSTR ? 2:1);
			else
				colSizeInBytes = 0;

			if (col.GetIsLong() ||
					cTotalLength + colSizeInBytes > cMaxColLengthPerCons)
				continue;

			// put this column in the list
			cTotalLength += colSizeInBytes;

			cons.AddColumn(col.GetColID());
			index++;
		}
	}

	odtLog << "Constraint has " << cons.cColumns() << " columns\n";
	CHECK(AddConstraintAndCheck(m_pITDWC, &Table.GetTableID(), cons), S_OK);

	TESTC_(cons.MakeConstraintName(), S_OK);
	// try the same when creating a table
	if (CHECK(CreateAndCheckTableWithConstraints(m_pITDWC, NULL, NULL,
			m_cColumnDesc, rgNewColumnDesc, 1, cons, IID_IRowset, 0, NULL, 
			&pTableID, NULL), S_OK))
	{
		CHECK(DropTableAndCheck(pTableID, m_pITDWC), S_OK);
		ReleaseDBID(pTableID, TRUE);
	}

CLEANUP:
	ReleaseColumnDesc(rgNewColumnDesc, m_cColumnDesc, TRUE);
	Table.DropTable();
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(4)
//*-----------------------------------------------------------------------
// @mfunc Create several unique constraints on a table, no overlapping
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCAddConstraint_UNIQUE::Variation_4()
{ 
	TBEGIN
	CTable				Table(m_pThisTestModule->m_pIUnknown2, (LPWSTR)gwszModuleName);
	CUniqueCons			cons;
	CUniqueCons			cons2;
	CCol				col;

	TESTC_(Table.CreateTable(0, 0), S_OK);
	Table.AddInfoFromColumnsSchemaRowset(m_pITDWC, Table.GetTableName());
	TESTC_PROVIDER(4 <= Table.CountColumnsOnTable());

	// choose 2 columns and create a unique constraint on them
	TESTC_(Table.GetColInfo(4, col), S_OK);
	cons.AddColumn(col.GetColID());
	TESTC_(Table.GetColInfo(2, col), S_OK);
	cons.AddColumn(col.GetColID());
	TESTC_(AddConstraintAndCheck(m_pITDWC, &Table.GetTableID(), cons), S_OK);

	// choose another 2 columns and create a unique constraint
	TESTC_(Table.GetColInfo(3, col), S_OK);
	cons2.AddColumn(col.GetColID());
	TESTC_(Table.GetColInfo(1, col), S_OK);
	cons2.AddColumn(col.GetColID());
	TESTC_(AddConstraintAndCheck(m_pITDWC, &Table.GetTableID(), cons2), S_OK);

CLEANUP:
	Table.DropTable();
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(5)
//*-----------------------------------------------------------------------
// @mfunc Create multiple, overlapping constraints on a table
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCAddConstraint_UNIQUE::Variation_5()
{ 
	TBEGIN
	CTable				Table(m_pThisTestModule->m_pIUnknown2, (LPWSTR)gwszModuleName);
	CUniqueCons			cons;
	CUniqueCons			cons2;
	CCol				col;

	TESTC_(Table.CreateTable(0, 0), S_OK);
	Table.AddInfoFromColumnsSchemaRowset(m_pITDWC, Table.GetTableName());
	TESTC_PROVIDER(3 <= Table.CountColumnsOnTable());

	// choose 2 columns and create a unique constraint on them
	TESTC_(Table.GetColInfo(3, col), S_OK);
	cons.AddColumn(col.GetColID());
	TESTC_(Table.GetColInfo(2, col), S_OK);
	cons.AddColumn(col.GetColID());
	TESTC_(AddConstraintAndCheck(m_pITDWC, &Table.GetTableID(), cons), S_OK);

	// choose another 2 columns and create a unique constraint
	TESTC_(Table.GetColInfo(1, col), S_OK);
	cons2.AddColumn(col.GetColID());
	TESTC_(Table.GetColInfo(3, col), S_OK);
	cons2.AddColumn(col.GetColID());
	TESTC_(AddConstraintAndCheck(m_pITDWC, &Table.GetTableID(), cons2), S_OK);

CLEANUP:
	Table.DropTable();
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(6)
//*-----------------------------------------------------------------------
// @mfunc Create a constraint, drop it and recreate it
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCAddConstraint_UNIQUE::Variation_6()
{ 
	TBEGIN
	CTable				Table(m_pThisTestModule->m_pIUnknown2, (LPWSTR)gwszModuleName);
	CUniqueCons			cons;
	CCol				col;

	TESTC_(Table.CreateTable(0, 0), S_OK);
	Table.AddInfoFromColumnsSchemaRowset(m_pITDWC, Table.GetTableName());

	// choose 1 column and create a unique constraint on them
	TESTC_(Table.GetColInfo(1, col), S_OK);
	cons.AddColumn(col.GetColID());

	TESTC_(AddConstraintAndCheck(m_pITDWC, &Table.GetTableID(), cons), S_OK);

	// drop the constraint and recreate it
	TESTC_(DropConstraintAndCheck(m_pITDWC, &Table.GetTableID(), cons), S_OK);
	TESTC_(AddConstraintAndCheck(m_pITDWC, &Table.GetTableID(), cons), S_OK);

CLEANUP:
	Table.DropTable();
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(7)
//*-----------------------------------------------------------------------
// @mfunc Create a constraint on a null column
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCAddConstraint_UNIQUE::Variation_7()
{ 
	TBEGIN
	CTable				Table(m_pThisTestModule->m_pIUnknown2, (LPWSTR)gwszModuleName);
	CUniqueCons			cons;
	CCol				col;
	DBCOLUMNDESC		*rgNewColumnDesc = NULL;

	// create a new table with a NULLABLE column
	DuplicateColumnDesc(m_rgColumnDesc, m_cColumnDesc, &rgNewColumnDesc);
	// by setting DBCOLUMNDESC, all nullable type column are created as nullable 
	Table.SetColumnDesc(rgNewColumnDesc, m_cColumnDesc);
	Table.SetBuildColumnDesc(FALSE);
	
	TESTC_(Table.CreateTable(0, 0), S_OK);
	Table.AddInfoFromColumnsSchemaRowset(m_pITDWC, Table.GetTableName());

	// identify a nullable column
	TESTC_PROVIDER(S_OK == Table.GetColInfo(IsCColNullable, col));

	cons.AddColumn(col.GetColID());

	TESTC_(AddConstraintAndCheck(m_pITDWC, &Table.GetTableID(), cons), S_OK);

CLEANUP:
	Table.DropTable();
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(8)
//*-----------------------------------------------------------------------
// @mfunc Create a contraint on a not nullable column
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCAddConstraint_UNIQUE::Variation_8()
{ 
	TBEGIN
	CTable				Table(m_pThisTestModule->m_pIUnknown2, (LPWSTR)gwszModuleName);
	CUniqueCons			cons;
	CCol				col;
	DBCOLUMNDESC		*rgNewColumnDesc = NULL;
	DBID				*pTableID			= NULL;

	// create a new table with a NOT NULLABLE column
	DuplicateColumnDesc(m_rgColumnDesc, m_cColumnDesc, &rgNewColumnDesc);

	// create a new table with a NOT NULLABLE column
	DuplicateColumnDesc(m_rgColumnDesc, m_cColumnDesc, &rgNewColumnDesc);
	SetProperty(&rgNewColumnDesc[0].rgPropertySets, &rgNewColumnDesc[0].cPropertySets,
			DBPROP_COL_NULLABLE, 
			VT_BOOL, (LPVOID)VARIANT_FALSE, 
			DBPROPOPTIONS_REQUIRED);
	Table.SetColumnDesc(rgNewColumnDesc, m_cColumnDesc);
	Table.SetBuildColumnDesc(FALSE);
	
	TESTC_(Table.CreateTable(0, 0), S_OK);
	Table.AddInfoFromColumnsSchemaRowset(m_pITDWC, Table.GetTableName());

	// identify a nullable column
	TESTC_PROVIDER(S_OK == Table.GetColInfo(IsCColNotNullable, col));

	cons.AddColumn(col.GetColID());

	TESTC_(AddConstraintAndCheck(m_pITDWC, &Table.GetTableID(), cons), S_OK);

	// try the same when creating a table
	TESTC_(cons.MakeConstraintName(), S_OK);
	if (CHECK(CreateAndCheckTableWithConstraints(m_pITDWC, NULL, NULL,
			m_cColumnDesc, rgNewColumnDesc, 1, cons, IID_IRowset, 0, NULL, 
			&pTableID, NULL), S_OK))
	{
		CHECK(DropTableAndCheck(pTableID, m_pITDWC), S_OK);
		ReleaseDBID(pTableID, TRUE);
	}

CLEANUP:
	Table.DropTable();
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(9)
//*-----------------------------------------------------------------------
// @mfunc Create a constraint on a column that has a default value
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCAddConstraint_UNIQUE::Variation_9()
{ 
	TBEGIN
	CTable					Table(m_pThisTestModule->m_pIUnknown2, (LPWSTR)gwszModuleName);
	CUniqueCons				cons;
	CCol					col;
	DBCOLUMNDESC			*rgNewColumnDesc = NULL;
	VARIANT					value;
	DBORDINAL				indexCol;
	CList<WCHAR *,WCHAR *>	NativeTypesList;
	CList<DBTYPE,DBTYPE>	ProviderTypesList;
	DBID				*pTableID			= NULL;

	Table.CreateTypeColInfo(NativeTypesList, ProviderTypesList);
	// create a new table with a NULLABLE column
	DuplicateColumnDesc(m_rgColumnDesc, m_cColumnDesc, &rgNewColumnDesc);
	// by setting DBCOLUMNDESC, all nullable type column are created as nullable 
	Table.SetColumnDesc(rgNewColumnDesc, m_cColumnDesc);
	// create a default value on one of the columns
	VariantInit(&value);
	indexCol = 2;
	if (rgNewColumnDesc[indexCol-1].pwszTypeName)
		odtLog << "Default value on type " << rgNewColumnDesc[indexCol-1].pwszTypeName << "\n";
	GetDefaultValue(&rgNewColumnDesc[indexCol-1], &value, &Table);
	SetDefaultProperty(&rgNewColumnDesc[indexCol-1].rgPropertySets, &rgNewColumnDesc[indexCol-1].cPropertySets,
				&value, DBPROPOPTIONS_REQUIRED);	// might be not supported
	VariantClear(&value);

	Table.SetBuildColumnDesc(FALSE);
	
	TESTC_PROVIDER(S_OK == Table.CreateTable(0, 0));
	Table.AddInfoFromColumnsSchemaRowset(m_pITDWC, Table.GetTableName());

	// identify a nullable column
	TESTC_(Table.GetColInfo(indexCol, col), S_OK);

	cons.AddColumn(col.GetColID());

	TESTC_(AddConstraintAndCheck(m_pITDWC, &Table.GetTableID(), cons), S_OK);

	// try the same when creating a table
	TESTC_(cons.MakeConstraintName(), S_OK);
	if (CHECK(CreateAndCheckTableWithConstraints(m_pITDWC, NULL, NULL,
			m_cColumnDesc, rgNewColumnDesc, 1, cons, IID_IRowset, 0, NULL, 
			&pTableID, NULL), S_OK))
	{
		CHECK(DropTableAndCheck(pTableID, m_pITDWC), S_OK);
		ReleaseDBID(pTableID, TRUE);
	}

CLEANUP:
	Table.DropTable();
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(10)
//*-----------------------------------------------------------------------
// @mfunc Create a constraint on a column defined as a primary key
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCAddConstraint_UNIQUE::Variation_10()
{ 
	TBEGIN
	CTable					Table(m_pThisTestModule->m_pIUnknown2, (LPWSTR)gwszModuleName);
	CUniqueCons				cons;
	CCol					col;
	DBCOLUMNDESC			*rgNewColumnDesc = NULL;
	DBORDINAL				indexCol;
	CList<WCHAR *,WCHAR *>	NativeTypesList;
	CList<DBTYPE,DBTYPE>	ProviderTypesList;
	DBID					*pTableID			= NULL;

	Table.CreateTypeColInfo(NativeTypesList, ProviderTypesList);
	// create a new table with a NULLABLE column
	DuplicateColumnDesc(m_rgColumnDesc, m_cColumnDesc, &rgNewColumnDesc);
	// by setting DBCOLUMNDESC, all nullable type column are created as nullable 
	Table.SetColumnDesc(rgNewColumnDesc, m_cColumnDesc);
	// create a default value on one of the columns
	indexCol = 3;
	if (rgNewColumnDesc[indexCol-1].pwszTypeName)
		odtLog << "Default value on type " << rgNewColumnDesc[indexCol-1].pwszTypeName << "\n";
	SetProperty(&rgNewColumnDesc[indexCol-1].rgPropertySets, &rgNewColumnDesc[indexCol-1].cPropertySets,
				DBPROP_COL_PRIMARYKEY, 
				VT_BOOL, (LPVOID)VARIANT_TRUE, 
				DBPROPOPTIONS_REQUIRED);

	Table.SetBuildColumnDesc(FALSE);
	
	TESTC_PROVIDER(S_OK == Table.CreateTable(0, 0));
	Table.AddInfoFromColumnsSchemaRowset(m_pITDWC, Table.GetTableName());

	// identify a nullable column
	TESTC_(Table.GetColInfo(indexCol, col), S_OK);

	cons.AddColumn(col.GetColID());

	TESTC_(AddConstraintAndCheck(m_pITDWC, &Table.GetTableID(), cons), S_OK);

	// try the same when creating a table
	cons.MakeConstraintName();
	if (CHECK(CreateAndCheckTableWithConstraints(m_pITDWC, NULL, NULL,
			m_cColumnDesc, rgNewColumnDesc, 1, cons, IID_IRowset, 0, NULL, 
			&pTableID, NULL), S_OK))
	{
		CHECK(DropTableAndCheck(pTableID, m_pITDWC), S_OK);
		ReleaseDBID(pTableID, TRUE);
	}

CLEANUP:
	Table.DropTable();
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(11)
//*-----------------------------------------------------------------------
// @mfunc Create a constraint on a column defined as a foreign key
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCAddConstraint_UNIQUE::Variation_11()
{ 
	TBEGIN
	CTable					RefTable(m_pThisTestModule->m_pIUnknown2, (LPWSTR)gwszModuleName);
	CUniqueCons				cons;
	CCol					col, col2;
	DBCOLUMNDESC			*rgNewColumnDesc = NULL;
	DBORDINAL				indexCol;
	CTable					BaseTable(m_pThisTestModule->m_pIUnknown2, (LPWSTR)gwszModuleName);
	CForeignKeyCons			cons2(NULL, m_SupportedMatchType);
	DBCONSTRAINTDESC		*pConsDesc2 = (DBCONSTRAINTDESC*)cons2;

	TESTC_(RefTable.CreateTable(0, 0), S_OK);
	RefTable.AddInfoFromColumnsSchemaRowset(m_pITDWC, RefTable.GetTableName());
	TESTC_(BaseTable.CreateTable(0, 0), S_OK);
	BaseTable.AddInfoFromColumnsSchemaRowset(m_pITDWC, BaseTable.GetTableName());
	
	// select a column
	TESTC(RefTable.CountColumnsOnTable() == BaseTable.CountColumnsOnTable())
	indexCol = 1;
	TESTC_(RefTable.GetColInfo(indexCol, col2), S_OK);
	TESTC_(BaseTable.GetColInfo(indexCol, col), S_OK);

	TESTC_(AddUniqueConstraint(&RefTable, 1, &indexCol), S_OK);
	
	// build the foreign key constraint, use corresponding columns in tables
	// set column on base table
	cons2.AddColumn(col2.GetColID());

	// set foreign column
	cons2.AddForeignKeyColumn(col.GetColID());

	// set reference table
	cons2.SetReferencedTableID(&RefTable.GetTableID());

	// add the foreign key constraint
	TESTC_(AddConstraintAndCheck(m_pITDWC, &BaseTable.GetTableID(), cons2), S_OK);

	// prepare and add the unique constraint on the column involved in a foreign key 
	cons.AddColumn(col.GetColID());	
	TESTC_(AddConstraintAndCheck(m_pITDWC, &BaseTable.GetTableID(), cons), S_OK);

CLEANUP:
	BaseTable.DropTable();
	RefTable.DropTable();
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(12)
//*-----------------------------------------------------------------------
// @mfunc Create a constraint on a column that is included in an index
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCAddConstraint_UNIQUE::Variation_12()
{ 
	TBEGIN
	CTable					Table(m_pThisTestModule->m_pIUnknown2, (LPWSTR)gwszModuleName);
	CUniqueCons				cons;
	CCol					col;

	// create a table and an index
	TESTC_(Table.CreateTable(0, 1), S_OK);
	Table.AddInfoFromColumnsSchemaRowset(m_pITDWC, Table.GetTableName());
	
	// select a column (the one used in index)
	TESTC_(Table.GetColInfo(1, col), S_OK);

	cons.AddColumn(col.GetColID());
	TESTC_(AddConstraintAndCheck(m_pITDWC, &Table.GetTableID(), cons), S_OK);

	TESTC_(cons.MakeConstraintName(), S_OK);
	
CLEANUP:
	Table.DropTable();
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(13)
//*-----------------------------------------------------------------------
// @mfunc Use the name of an already existing constraint
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCAddConstraint_UNIQUE::Variation_13()
{ 
	TBEGIN

	CTable					Table(m_pITDWC, (LPWSTR)gwszModuleName);
	CTable					ReferencedTable(m_pITDWC, (LPWSTR)gwszModuleName);
	CUniqueCons				cons;
	CUniqueCons				UniqueCons;
	CPrimaryKeyCons			PKCons;
	CCheckCons				CheckCons;
	CForeignKeyCons			FKCons;
	DBORDINAL				rgCol[] = {1};
	HRESULT					hr;
	DBCOLUMNDESC			*rgNewColumnDesc	= NULL;
	DBID					*pTableID			= NULL;

	// create a new table with a NOT NULLABLE column
	DuplicateColumnDesc(m_rgColumnDesc, m_cColumnDesc, &rgNewColumnDesc);

	// create a table
	TESTC_(CreateTableWithNoNullableColumns(&Table, 0), S_OK);
	TESTC_(ReferencedTable.CreateTable(0), S_OK);
	ReferencedTable.AddInfoFromColumnsSchemaRowset(m_pITDWC, ReferencedTable.GetTableName());
	TESTC_(AddUniqueConstraint(&ReferencedTable, 1), S_OK);
	
	// create a unique constraint
	TESTC_(UniqueCons.SetConstraint(&Table, 1), S_OK);
	TESTC_(AddConstraintAndCheck(m_pITDWC, &Table.GetTableID(), UniqueCons), S_OK);

	// create a check constraint
	CheckCons.SetLTCheckConstraint(&Table, 1, 60);
	TESTC_(AddConstraintAndCheck(m_pITDWC, &Table.GetTableID(), CheckCons), S_OK);

	// create a PK constraint
	TESTC_(PKCons.SetConstraint(&Table, 1), S_OK);
	TESTC_(AddConstraintAndCheck(m_pITDWC, &Table.GetTableID(), PKCons), S_OK);

	// create a FK constraint
	TESTC_(FKCons.SetConstraint(&Table, NUMELEM(rgCol), rgCol, 
		&ReferencedTable, NUMELEM(rgCol), rgCol, m_SupportedMatchType), S_OK);
	TESTC_(AddConstraintAndCheck(m_pITDWC, &Table.GetTableID(), FKCons), S_OK);

	// add the constraint again, this time on other column (if possible)
	TESTC_(cons.SetConstraint(&Table, 2), S_OK);

	odtLog << "Unique constraint duplicate unique constraint name\n";
	cons.SetConstraintID(UniqueCons.GetConstraintID());
	CHECK(AddConstraintAndCheck(m_pITDWC, &Table.GetTableID(), cons), DB_E_DUPLICATECONSTRAINTID);
	// try the same when creating a table
	if (!CHECK(hr = CreateAndCheckTableWithConstraints(m_pITDWC, NULL, NULL,
			m_cColumnDesc, rgNewColumnDesc, 1, cons, IID_IRowset, 0, NULL, 
			&pTableID, NULL), DB_E_DUPLICATECONSTRAINTID) && SUCCEEDED(hr))
	{
		CHECK(DropTableAndCheck(pTableID, m_pITDWC), S_OK);
		ReleaseDBID(pTableID, TRUE);
	}

	odtLog << "Unique constraint duplicate check constraint name\n";
	cons.SetConstraintID(CheckCons.GetConstraintID());
	CHECK(AddConstraintAndCheck(m_pITDWC, &Table.GetTableID(), cons), DB_E_DUPLICATECONSTRAINTID);
	// try the same when creating a table
	if (!CHECK(hr = CreateAndCheckTableWithConstraints(m_pITDWC, NULL, NULL,
			m_cColumnDesc, rgNewColumnDesc, 1, cons, IID_IRowset, 0, NULL, 
			&pTableID, NULL), DB_E_DUPLICATECONSTRAINTID) && SUCCEEDED(hr))
	{
		CHECK(DropTableAndCheck(pTableID, m_pITDWC), S_OK);
		ReleaseDBID(pTableID, TRUE);
	}

	odtLog << "Unique constraint duplicate primary key constraint name\n";
	cons.SetConstraintID(PKCons.GetConstraintID());
	CHECK(AddConstraintAndCheck(m_pITDWC, &Table.GetTableID(), cons), DB_E_DUPLICATECONSTRAINTID);
	// try the same when creating a table
	if (!CHECK(hr = CreateAndCheckTableWithConstraints(m_pITDWC, NULL, NULL,
			m_cColumnDesc, rgNewColumnDesc, 1, cons, IID_IRowset, 0, NULL, 
			&pTableID, NULL), DB_E_DUPLICATECONSTRAINTID) && SUCCEEDED(hr))
	{
		CHECK(DropTableAndCheck(pTableID, m_pITDWC), S_OK);
		ReleaseDBID(pTableID, TRUE);
	}

	odtLog << "Unique constraint duplicate foreign key constraint name\n";
	cons.SetConstraintID(FKCons.GetConstraintID());
	CHECK(AddConstraintAndCheck(m_pITDWC, &Table.GetTableID(), cons), DB_E_DUPLICATECONSTRAINTID);
	// try the same when creating a table
	if (!CHECK(hr = CreateAndCheckTableWithConstraints(m_pITDWC, NULL, NULL,
			m_cColumnDesc, rgNewColumnDesc, 1, cons, IID_IRowset, 0, NULL, 
			&pTableID, NULL), DB_E_DUPLICATECONSTRAINTID) && SUCCEEDED(hr))
	{
		CHECK(DropTableAndCheck(pTableID, m_pITDWC), S_OK);
		ReleaseDBID(pTableID, TRUE);
	}

CLEANUP:
	ReleaseColumnDesc(rgNewColumnDesc, m_cColumnDesc, TRUE);
	CHECK(Table.DropTable(), S_OK);
	CHECK(ReferencedTable.DropTable(), S_OK);
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(14)
//*-----------------------------------------------------------------------
// @mfunc Constraint is created in a different catalog
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCAddConstraint_UNIQUE::Variation_14()
{ 
	TBEGIN
	CTable					Table(m_pThisTestModule->m_pIUnknown2, (LPWSTR)gwszModuleName);
	CUniqueCons				cons;
	DBCONSTRAINTDESC		*pConsDesc = (DBCONSTRAINTDESC*)cons;
	CCol					col;
	DBORDINAL				indxCat = 0;
	CCatalogs				Catalogs(m_pIOpenRowset);
	IDBProperties			*pIDBProperties = NULL;
	CPropSets				PropSets;
	WCHAR					*pwszCurrentCatalog = NULL;
	WCHAR					*pwszQualTableName = NULL;
	WCHAR					*pwszCatalogName = NULL;
	WCHAR					*pwszSchemaName = NULL;

	TESTC_PROVIDER(SettableProperty(DBPROP_CURRENTCATALOG, DBPROPSET_DATASOURCE, m_pIDBInitialize));
	TESTC_PROVIDER(1 < Catalogs.cCatalogs());

	// create a table and an index
	TESTC_(Table.CreateTable(0, 0), S_OK);
	Table.AddInfoFromColumnsSchemaRowset(m_pITDWC, Table.GetTableName());
	
	// select column
	TESTC_(Table.GetColInfo(1, col), S_OK);

	// set DBID of the table to its qualified form
	TESTC(DBKIND_NAME == Table.GetTableID().eKind);

	TESTC(GetCatalogSchemaNames(Table.GetTableName(), &pwszCatalogName, &pwszSchemaName));

	//Construct a fully Qualified TableName...
	TESTC_(m_pTable->GetQualifiedName(pwszCatalogName, pwszSchemaName, Table.GetTableName(), &pwszQualTableName),S_OK);
	Table.SetTableName(pwszQualTableName);

	// change the current catalog
	TESTC(GetProperty(DBPROP_CURRENTCATALOG, DBPROPSET_DATASOURCE, m_pIDBInitialize,
		&pwszCurrentCatalog));
	TESTC(NULL != pwszCurrentCatalog);

	TESTC(VerifyInterface(m_pIDBInitialize, IID_IDBProperties, DATASOURCE_INTERFACE, (IUnknown**)&pIDBProperties));

	if (0 == wcscmp(pwszCurrentCatalog, Catalogs[0]))
		indxCat++;

	CHECK(PropSets.AddProperty(DBPROP_CURRENTCATALOG, DBPROPSET_DATASOURCE, VT_BSTR, (LPVOID)Catalogs[indxCat]), S_OK);
	TESTC_PROVIDER(S_OK == pIDBProperties->SetProperties(PropSets, PropSets));

	// alloc memory for column array
	cons.AddColumn(col.GetColID());

	// try to make column unique
	TESTC_(AddConstraintAndCheck(m_pITDWC, &Table.GetTableID(), cons), S_OK);

CLEANUP:
	if (CHECK(PropSets.SetProperty(DBPROP_CURRENTCATALOG, DBPROPSET_DATASOURCE, VT_BSTR, (LPVOID)pwszCurrentCatalog), S_OK))
		CHECK(pIDBProperties->SetProperties(PropSets, PropSets), S_OK);

	SAFE_FREE(pwszCatalogName);
	SAFE_FREE(pwszSchemaName);
	SAFE_FREE(pwszQualTableName);
	SAFE_FREE(pwszCurrentCatalog);
	SAFE_RELEASE(pIDBProperties);
	Table.DropTable();
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(15)
//*-----------------------------------------------------------------------
// @mfunc create a unique constraint on a non empty table
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCAddConstraint_UNIQUE::Variation_15()
{ 
	TBEGIN
	CTable					Table(m_pThisTestModule->m_pIUnknown2, (LPWSTR)gwszModuleName);

	// create a table and an index
	TESTC_(Table.CreateTable(10, 0), S_OK);
	Table.AddInfoFromColumnsSchemaRowset(m_pITDWC, Table.GetTableName());
	
	// select column
	TESTC_(AddUniqueConstraint(&Table, 1), S_OK);

CLEANUP:
	Table.DropTable();
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(16)
//*-----------------------------------------------------------------------
// @mfunc Create a unique constraints on a column that has doubled values
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCAddConstraint_UNIQUE::Variation_16()
{ 
	TBEGIN
	CTable					Table(m_pThisTestModule->m_pIUnknown2, (LPWSTR)gwszModuleName);

	// create a table and an index
	TESTC_(Table.CreateTable(0, 0), S_OK);
	Table.AddInfoFromColumnsSchemaRowset(m_pITDWC, Table.GetTableName());

	// double one of the rows
	TESTC_PROVIDER(S_OK == Table.Insert(5));
	TESTC_PROVIDER(S_OK == Table.Insert(5));
	
	// add the constraint
	TESTC_(AddUniqueConstraint(&Table, 1), DB_E_SCHEMAVIOLATION);

CLEANUP:
	Table.DropTable();
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(17)
//*-----------------------------------------------------------------------
// @mfunc Abort retaining
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCAddConstraint_UNIQUE::Variation_17()
{
	CAddUniqueConsTxnAdapter	TxnAdapter(this);
	CTransactionLocal			TxnLocal;

	return TxnLocal.DoTransactionTest(m_pITDWC, &TxnAdapter,
		TRUE,		// DDL
		TRUE,		// Abort
		TRUE		// Retaining
		);
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(18)
//*-----------------------------------------------------------------------
// @mfunc Abort non retaining
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCAddConstraint_UNIQUE::Variation_18()
{ 
	CAddUniqueConsTxnAdapter	TxnAdapter(this);
	CTransactionLocal			TxnLocal;

	return TxnLocal.DoTransactionTest(m_pITDWC, &TxnAdapter,
		TRUE,		// DDL
		TRUE,		// Abort
		FALSE		// Non Retaining
		);
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(19)
//*-----------------------------------------------------------------------
// @mfunc Commit retaining
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCAddConstraint_UNIQUE::Variation_19()
{ 
	CAddUniqueConsTxnAdapter	TxnAdapter(this);
	CTransactionLocal			TxnLocal;

	return TxnLocal.DoTransactionTest(m_pITDWC, &TxnAdapter,
		TRUE,		// DDL
		FALSE,		// Commit
		TRUE		// Retaining
		);
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(20)
//*-----------------------------------------------------------------------
// @mfunc Commit non retaining
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCAddConstraint_UNIQUE::Variation_20()
{ 
	CAddUniqueConsTxnAdapter	TxnAdapter(this);
	CTransactionLocal			TxnLocal;

	return TxnLocal.DoTransactionTest(m_pITDWC, &TxnAdapter,
		TRUE,		// DDL
		FALSE,		// Commit
		TRUE		// Retaining
		);

} 
// }} TCW_VAR_PROTOTYPE_END


int TCAddConstraint_UNIQUE::Variation_21() {
	TBEGIN

	CLimitTable			Table;

	TESTC_(Table.CheckUniqueKeyLimit(), S_OK);
CLEANUP:
	TRETURN
}

// {{ TCW_TERMINATE_METHOD
//*-----------------------------------------------------------------------
// @mfunc TestCase Termination Routine 
//
// @rdesc TEST_PASS or TEST_FAIL 
//
BOOL TCAddConstraint_UNIQUE::Terminate()
{ 
	// TO DO:  Add your own code here 

// {{ TCW_TERM_BASECLASS_CHECK2
	return(TCITableDefinition::Terminate());
} 	// }}
// }} TCW_TERMINATE_METHOD_END
// }} TCW_TC_PROTOTYPE_END


// {{ TCW_TC_PROTOTYPE(TCAddConstraint_PRIMARYKEY)
//*-----------------------------------------------------------------------
//| Test Case:		TCAddConstraint_PRIMARYKEY - Testcase for ITableDefinitionWithConstraints::AddConstraint used with DBCONSTRAINTTYPE_PRIMARYKEY
//| Created:  	7/29/99
//*-----------------------------------------------------------------------

//*-----------------------------------------------------------------------
// @mfunc TestCase Initialization Routine
//
// @rdesc TRUE or FALSE
//
BOOL TCAddConstraint_PRIMARYKEY::Init()
{ 
	// {{ TCW_INIT_BASECLASS_CHECK
	if(TCITableDefinition::Init())
	// }}
	{ 
		// TO DO:  Add your own code here 
		if (m_pITDWC == NULL)
		{
			odtLog << "ITableDefinitionWithConstraints is not supported.\n";
			return TEST_SKIPPED;
		}
		return TRUE;
	} 
	return FALSE;
} 




// {{ TCW_VAR_PROTOTYPE(1)
//*-----------------------------------------------------------------------
// @mfunc Create a table and try to apply the constraint on each column
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCAddConstraint_PRIMARYKEY::Variation_1()
{ 
	TBEGIN
	CTable				Table(m_pThisTestModule->m_pIUnknown2, (LPWSTR)gwszModuleName);
	DBORDINAL			index;
	CPrimaryKeyCons		cons;
	DBCOLUMNDESC		*rgNewColumnDesc	= NULL;
	DBID				*pTableID			= NULL;
	HRESULT				hrExpected			= S_OK;
	DBORDINAL			cColCount			= 0,
						cTotalLength		= 0,
						start				= 1,
						cTotalColsInTable	= 0;
	ULONG				ulNumberOfTests		= 0;


	// create a new table with a NOT NULLABLE column
	DuplicateColumnDesc(m_rgColumnDesc, m_cColumnDesc, &rgNewColumnDesc);

	// create the base table
	TESTC_(CreateTableWithNoNullableColumns(&Table, 0), S_OK);

//	TESTC_(Table.CreateTable(0, 0), S_OK);
	Table.AddInfoFromColumnsSchemaRowset(m_pITDWC, Table.GetTableName());

	// build the constraint
	cTotalColsInTable	=	Table.CountColumnsOnTable();

	while(start < cTotalColsInTable) {	

		cTotalLength	=	0;
		hrExpected		=	S_OK;
		
		cons.ReleaseColumnList();

		for (index = start, cColCount = 0; index <= Table.CountColumnsOnTable() &&
				cColCount < cMaxColsPerCons; index++, cColCount++)
		{
			CCol	col;
			DBORDINAL	colSizeInBytes = 0; //how many bytes the column contributes into maximum size of constraint
	
			TESTC_(Table.GetColInfo(index, col), S_OK);

			// Note: col.GetColumnSize returns length for string data types and we need size in bytes
			//			so multiply ColumnSize by 2 for WSTR
			if(col.GetIsFixedLength() )
				colSizeInBytes = col.GetColumnSize() * (col.GetProviderType()==DBTYPE_WSTR ? 2:1);
			else
				colSizeInBytes = 0;

			if (col.GetIsLong() ||
					cTotalLength + colSizeInBytes > cMaxColLengthPerCons)
				continue;

			cTotalLength += colSizeInBytes;

			cons.AddColumn(col.GetColID());
		}

		if (cColCount)
		{
			ulNumberOfTests++;

			CHECK(AddConstraintAndCheck(m_pITDWC, &Table.GetTableID(), cons), hrExpected);
			if (hrExpected == S_OK) {
				CHECK(DropConstraintAndCheck(m_pITDWC, &Table.GetTableID(), cons), S_OK);
			}

			// try the same when creating a table
			TESTC_(cons.MakeConstraintName(), S_OK);
			CHECK(CreateAndCheckTableWithConstraints(m_pITDWC, NULL, NULL,
					m_cColumnDesc, rgNewColumnDesc, 1, cons, IID_IRowset, 0, NULL, 
					&pTableID, NULL), hrExpected);
			
			if (hrExpected==S_OK)
			{
				CHECK(DropTableAndCheck(pTableID, m_pITDWC), S_OK);
					ReleaseDBID(pTableID, TRUE);	
			}
		}

		start = index;
	}
	TESTC(ulNumberOfTests>0)

CLEANUP:
	ReleaseColumnDesc(rgNewColumnDesc, m_cColumnDesc, TRUE);
	Table.DropTable();
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END





// {{ TCW_VAR_PROTOTYPE(2)
//*-----------------------------------------------------------------------
// @mfunc Set a primary key constraint on each type of column
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCAddConstraint_PRIMARYKEY::Variation_2()
{ 
	TBEGIN
	CTable				Table(m_pThisTestModule->m_pIUnknown2, (LPWSTR)gwszModuleName);
	DBORDINAL			index;
	CPrimaryKeyCons		cons;
	DBCOLUMNDESC		*rgNewColumnDesc	= NULL;
	DBID				*pTableID			= NULL;
	HRESULT				hrExpected			= S_OK;

	// create a new table with a NOT NULLABLE column
	DuplicateColumnDesc(m_rgColumnDesc, m_cColumnDesc, &rgNewColumnDesc);

	// create a base table without nullable columns
	TESTC_(CreateTableWithNoNullableColumns(&Table, 0), S_OK);

	// build the constraint
	for (index=1; index <= Table.CountColumnsOnTable(); index++)
	{
		CCol	col;

		TESTC_(Table.GetColInfo(index, col), S_OK);

		TESTC_(cons.ReleaseColumnList(), S_OK);
		cons.AddColumn(col.GetColID());

		odtLog << col.GetProviderTypeName() << "\n";

		// Depending on the type of column, set return value
	
		// Note: col.GetColumnSize returns length for string data types and we need size in bytes
		//			so multiply ColumnSize by 2 for WSTR
		if (col.GetIsLong() ||
			(col.GetIsFixedLength() && (col.GetColumnSize() * (col.GetProviderType()==DBTYPE_WSTR ? 2:1) > cMaxColLengthPerCons)))
			hrExpected = E_FAIL;
		else
			hrExpected = S_OK;
		
		CHECK(AddConstraintAndCheck(m_pITDWC, &Table.GetTableID(), cons), hrExpected);
		if (hrExpected == S_OK) {
			TESTC_(DropConstraintAndCheck(m_pITDWC, &Table.GetTableID(), cons), S_OK);
		}

		// try the same when creating a table
		TESTC_(cons.MakeConstraintName(), S_OK);
		CHECK(CreateAndCheckTableWithConstraints(m_pITDWC, NULL, NULL,
				m_cColumnDesc, rgNewColumnDesc, 1, cons, IID_IRowset, 0, NULL, 
				&pTableID, NULL), hrExpected);
		if (hrExpected == S_OK)
		{
			CHECK(DropTableAndCheck(pTableID, m_pITDWC), S_OK);
			ReleaseDBID(pTableID, TRUE);
		}	
	}

CLEANUP:
	ReleaseColumnDesc(rgNewColumnDesc, m_cColumnDesc, TRUE);
	Table.DropTable();
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(3)
//*-----------------------------------------------------------------------
// @mfunc Create a primary key constraint. Drop it. Create a primary key using the same name as before.
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCAddConstraint_PRIMARYKEY::Variation_3()
{ 
	TBEGIN
	CTable				Table(m_pThisTestModule->m_pIUnknown2, (LPWSTR)gwszModuleName);
	CPrimaryKeyCons		cons;
	DBCONSTRAINTDESC	*pConsDesc = (DBCONSTRAINTDESC*)cons;
	CCol				col;

	// create a base table without nullable columns
	TESTC_(CreateTableWithNoNullableColumns(&Table, 0), S_OK);

	// build the constraint

	// try to set all the columns as primary key
	TESTC_(Table.GetColInfo(1, col), S_OK);
	cons.AddColumn(col.GetColID());

	TESTC_(AddConstraintAndCheck(m_pITDWC, &Table.GetTableID(), cons), S_OK);
	TESTC_(DropConstraintAndCheck(m_pITDWC, &Table.GetTableID(), cons), S_OK);

	ReleaseDBID(&pConsDesc->rgColumnList[0], FALSE);
	TESTC_(Table.GetColInfo(2, col), S_OK);
	DuplicateDBID(*col.GetColID(), &pConsDesc->rgColumnList[0]);

	// create constraint with the same name as before, different column
	TESTC_(AddConstraintAndCheck(m_pITDWC, &Table.GetTableID(), cons), S_OK);

CLEANUP:
	Table.DropTable();
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(4)
//*-----------------------------------------------------------------------
// @mfunc Create multiple-columned primary key
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCAddConstraint_PRIMARYKEY::Variation_4()
{ 
	TBEGIN
	CTable				Table(m_pThisTestModule->m_pIUnknown2, (LPWSTR)gwszModuleName);
	CPrimaryKeyCons		cons;
	CCol				col;
	DBCOLUMNDESC		*rgNewColumnDesc = NULL;
	DBID				*pTableID			= NULL;

	// create a new table with a NOT NULLABLE column
	DuplicateColumnDesc(m_rgColumnDesc, m_cColumnDesc, &rgNewColumnDesc);

	// create a base table without nullable columns
	TESTC_(CreateTableWithNoNullableColumns(&Table, 0), S_OK);

	TESTC_(Table.GetColInfo(1, col), S_OK);
	cons.AddColumn(col.GetColID());

	TESTC_(Table.GetColInfo(2, col), S_OK);
	cons.AddColumn(col.GetColID());

	CHECK(AddConstraintAndCheck(m_pITDWC, &Table.GetTableID(), cons), S_OK);

	// try the same when creating a table
	TESTC_(cons.MakeConstraintName(), S_OK);
	if (CHECK(CreateAndCheckTableWithConstraints(m_pITDWC, NULL, NULL,
			m_cColumnDesc, rgNewColumnDesc, 1, cons, IID_IRowset, 0, NULL, 
			&pTableID, NULL), S_OK))
	{
		CHECK(DropTableAndCheck(pTableID, m_pITDWC), S_OK);
		ReleaseDBID(pTableID, TRUE);
	}

CLEANUP:
	ReleaseColumnDesc(rgNewColumnDesc, m_cColumnDesc, TRUE);
	Table.DropTable();
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(5)
//*-----------------------------------------------------------------------
// @mfunc Create multiple primary key constraints using successive calls
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCAddConstraint_PRIMARYKEY::Variation_5()
{ 
	TBEGIN
	HRESULT				hr;
	CTable				Table(m_pThisTestModule->m_pIUnknown2, (LPWSTR)gwszModuleName);
	DBCOLUMNDESC		*rgNewColumnDesc = NULL;
	DBID				*pTableID			= NULL;
	CPrimaryKeyCons		cons;
	CConsDescArray		consArray;
	CCol				col;

	// create a new table with a NOT NULLABLE column
	DuplicateColumnDesc(m_rgColumnDesc, m_cColumnDesc, &rgNewColumnDesc);

	// create a base table without nullable columns
	TESTC_(CreateTableWithNoNullableColumns(&Table, 0), S_OK);

	// build the constraint
	TESTC_(AddPrimaryKeyConstraint(&Table, 1), S_OK);
	TESTC_(AddPrimaryKeyConstraint(&Table, 1), DB_E_DUPLICATECONSTRAINTID);

	// try the same when creating a table

	// add a first PK constraint
	cons.AddColumn(&rgNewColumnDesc[0].dbcid);
	cons.AddColumn(&rgNewColumnDesc[1].dbcid);
	consArray.AddConsDesc(cons);
	
	// add a second PK constraint
	CHECK(cons.MakeConstraintName(), S_OK);
	cons.ReleaseColumnList();
	cons.AddColumn(&rgNewColumnDesc[2].dbcid);
	consArray.AddConsDesc(cons);

	if (!CHECK(hr = CreateAndCheckTableWithConstraints(m_pITDWC, NULL, NULL,
			m_cColumnDesc, rgNewColumnDesc, consArray, consArray, IID_IRowset, 0, NULL, 
			&pTableID, NULL), DB_E_DUPLICATECONSTRAINTID) && SUCCEEDED(hr))
	{
		CHECK(DropTableAndCheck(pTableID, m_pITDWC), S_OK);
		ReleaseDBID(pTableID, TRUE);
	}

CLEANUP:
	ReleaseColumnDesc(rgNewColumnDesc, m_cColumnDesc, TRUE);
	Table.DropTable();
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(6)
//*-----------------------------------------------------------------------
// @mfunc Successive calls, lists of columns overlap
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCAddConstraint_PRIMARYKEY::Variation_6()
{ 
	TBEGIN
	CTable				Table(m_pThisTestModule->m_pIUnknown2, (LPWSTR)gwszModuleName);
	CPrimaryKeyCons		cons;
	CPrimaryKeyCons		cons2;
	CCol				col;

	// create a base table without nullable columns
	TESTC_(CreateTableWithNoNullableColumns(&Table, 0), S_OK);

	// build the constraint
	TESTC_(Table.GetColInfo(1, col), S_OK);
	cons.AddColumn(col.GetColID());

	TESTC_(AddConstraintAndCheck(m_pITDWC, &Table.GetTableID(), cons), S_OK);

	TESTC_(Table.GetColInfo(2, col), S_OK);
	cons2.AddColumn(col.GetColID());

	// try create second constraint
	TESTC_(AddConstraintAndCheck(m_pITDWC, &Table.GetTableID(), cons2), DB_E_DUPLICATECONSTRAINTID);

	TESTC_(DropConstraintAndCheck(m_pITDWC, &Table.GetTableID(), cons), S_OK);

	TESTC_(AddConstraintAndCheck(m_pITDWC, &Table.GetTableID(), cons2), S_OK);

CLEANUP:
	Table.DropTable();
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(7)
//*-----------------------------------------------------------------------
// @mfunc Primary key constraint on a nullable column
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCAddConstraint_PRIMARYKEY::Variation_7()
{ 
	TBEGIN
	CTable				Table(m_pThisTestModule->m_pIUnknown2, (LPWSTR)gwszModuleName);
	CCol				col;
	DBCOLUMNDESC		*rgNewColumnDesc	= NULL;
	DBID				*pTableID			= NULL;
	CPrimaryKeyCons		cons;

	// create a new table with a NULLABLE column
	DuplicateColumnDesc(m_rgColumnDesc, m_cColumnDesc, &rgNewColumnDesc);
	SetProperty(&rgNewColumnDesc[0].rgPropertySets, &rgNewColumnDesc[0].cPropertySets,
			DBPROP_COL_NULLABLE, 
			VT_BOOL, (LPVOID)VARIANT_TRUE, 
			DBPROPOPTIONS_REQUIRED);
	Table.SetColumnDesc(rgNewColumnDesc, m_cColumnDesc);
	Table.SetBuildColumnDesc(FALSE);
	
	TESTC_(Table.CreateTable(0, 0), S_OK);
	Table.AddInfoFromColumnsSchemaRowset(m_pITDWC, Table.GetTableName());

	// identify a nullable column
	TESTC_PROVIDER(S_OK == Table.GetColInfo(IsCColNullable, col));


	CHECK(AddPrimaryKeyConstraint(&Table, col.GetColNum()), E_FAIL);

	// try the same when creating a table
	cons.AddColumn(&rgNewColumnDesc[0].dbcid);
	CHECK(CreateAndCheckTableWithConstraints(m_pITDWC, NULL, NULL,
			m_cColumnDesc, rgNewColumnDesc, 1, cons, IID_IRowset, 0, NULL, 
			&pTableID, NULL), E_FAIL);
	//
	//{
	//	CHECK(DropTableAndCheck(pTableID, m_pITDWC), S_OK);
	//	ReleaseDBID(pTableID, TRUE);
	//}

CLEANUP:
	Table.DropTable();
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(8)
//*-----------------------------------------------------------------------
// @mfunc Primary key constraint on a not nullable column
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCAddConstraint_PRIMARYKEY::Variation_8()
{ 
	TBEGIN
	CTable				Table(m_pThisTestModule->m_pIUnknown2, (LPWSTR)gwszModuleName);
	DBCOLUMNDESC		*rgNewColumnDesc = NULL;
	DBID				*pTableID			= NULL;
	CPrimaryKeyCons		cons;

	// create a new table with a NULLABLE column
	DuplicateColumnDesc(m_rgColumnDesc, m_cColumnDesc, &rgNewColumnDesc);
	SetProperty(&rgNewColumnDesc[0].rgPropertySets, &rgNewColumnDesc[0].cPropertySets,
			DBPROP_COL_NULLABLE, 
			VT_BOOL, (LPVOID)VARIANT_FALSE, 
			DBPROPOPTIONS_REQUIRED);
	Table.SetColumnDesc(rgNewColumnDesc, m_cColumnDesc);
	Table.SetBuildColumnDesc(FALSE);
	
	TESTC_(Table.CreateTable(0, 0), S_OK);
	Table.AddInfoFromColumnsSchemaRowset(m_pITDWC, Table.GetTableName());

	// add a primary key on a not nullable column
	CHECK(AddPrimaryKeyConstraint(&Table, 1), S_OK);

	// try the same when creating a table
	cons.AddColumn(&rgNewColumnDesc[0].dbcid);
	if (CHECK(CreateAndCheckTableWithConstraints(m_pITDWC, NULL, NULL,
			m_cColumnDesc, rgNewColumnDesc, 1, cons, IID_IRowset, 0, NULL, 
			&pTableID, NULL), S_OK))
	{
		CHECK(DropTableAndCheck(pTableID, m_pITDWC), S_OK);
		ReleaseDBID(pTableID, TRUE);
	}

CLEANUP:
	Table.DropTable();
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(9)
//*-----------------------------------------------------------------------
// @mfunc Primary key constraint on a column with a default value
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCAddConstraint_PRIMARYKEY::Variation_9()
{ 
	TBEGIN
	CTable					Table(m_pThisTestModule->m_pIUnknown2, (LPWSTR)gwszModuleName);
	DBCOLUMNDESC			*rgNewColumnDesc = NULL;
	VARIANT					value;
	CList<WCHAR *,WCHAR *>	NativeTypesList;
	CList<DBTYPE,DBTYPE>	ProviderTypesList;
	DBID					*pTableID = NULL;
	CPrimaryKeyCons			cons;

	Table.CreateTypeColInfo(NativeTypesList, ProviderTypesList);
	// create a new table with a NULLABLE column
	DuplicateColumnDesc(m_rgColumnDesc, m_cColumnDesc, &rgNewColumnDesc);
	VariantInit(&value);
	odtLog << "Default value on type " << rgNewColumnDesc[0].pwszTypeName << "\n";
	GetDefaultValue(&rgNewColumnDesc[0], &value, &Table);
	SetDefaultProperty(&rgNewColumnDesc[0].rgPropertySets, &rgNewColumnDesc[0].cPropertySets,
				&value, DBPROPOPTIONS_REQUIRED);	// might be not supported
	VariantClear(&value);
	SetProperty(&rgNewColumnDesc[0].rgPropertySets, &rgNewColumnDesc[0].cPropertySets,
			DBPROP_COL_NULLABLE, 
			VT_BOOL, (LPVOID)VARIANT_FALSE, 
			DBPROPOPTIONS_REQUIRED);
	Table.SetColumnDesc(rgNewColumnDesc, m_cColumnDesc);
	Table.SetBuildColumnDesc(FALSE);
	
	TESTC_(Table.CreateTable(0, 0), S_OK);
	Table.AddInfoFromColumnsSchemaRowset(m_pITDWC, Table.GetTableName());

	// add a PK on a column with a default value
	CHECK(AddPrimaryKeyConstraint(&Table, 1), S_OK);

	// try the same when creating a table
	cons.AddColumn(&rgNewColumnDesc[0].dbcid);
	if (CHECK(CreateAndCheckTableWithConstraints(m_pITDWC, NULL, NULL,
			m_cColumnDesc, rgNewColumnDesc, 1, cons, IID_IRowset, 0, NULL, 
			&pTableID, NULL), S_OK))
	{
		CHECK(DropTableAndCheck(pTableID, m_pITDWC), S_OK);
		ReleaseDBID(pTableID, TRUE);
	}

CLEANUP:
	Table.DropTable();
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(10)
//*-----------------------------------------------------------------------
// @mfunc Primary key constraint on a column defined as unique
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCAddConstraint_PRIMARYKEY::Variation_10()
{ 
	TBEGIN
	CTable				Table(m_pThisTestModule->m_pIUnknown2, (LPWSTR)gwszModuleName);
	DBCOLUMNDESC		*rgNewColumnDesc = NULL;
	DBID				*pTableID = NULL;
	CPrimaryKeyCons		cons;

	TESTC_PROVIDER(SettableProperty(DBPROP_COL_UNIQUE, DBPROPSET_COLUMN, m_pIDBInitialize));

	// create a new table with a NULLABLE column
	DuplicateColumnDesc(m_rgColumnDesc, m_cColumnDesc, &rgNewColumnDesc);
	SetProperty(&rgNewColumnDesc[0].rgPropertySets, &rgNewColumnDesc[0].cPropertySets,
			DBPROP_COL_UNIQUE, 
			VT_BOOL, (LPVOID)VARIANT_TRUE, 
			DBPROPOPTIONS_REQUIRED);
	SetProperty(&rgNewColumnDesc[0].rgPropertySets, &rgNewColumnDesc[0].cPropertySets,
			DBPROP_COL_NULLABLE, 
			VT_BOOL, (LPVOID)VARIANT_FALSE, 
			DBPROPOPTIONS_OPTIONAL);
	Table.SetColumnDesc(rgNewColumnDesc, m_cColumnDesc);
	Table.SetBuildColumnDesc(FALSE);

	TEST2C_(Table.CreateTable(0, 0), S_OK, DB_S_ERRORSOCCURRED);
	Table.AddInfoFromColumnsSchemaRowset(m_pITDWC, Table.GetTableName());

	// add PK on a unique column
	CHECK(AddPrimaryKeyConstraint(&Table, 1), S_OK);

	// try the same when creating a table
	CHECK(cons.MakeConstraintName(), S_OK);
	cons.AddColumn(&rgNewColumnDesc[0].dbcid);
	if (CHECK(CreateAndCheckTableWithConstraints(m_pITDWC, NULL, NULL,
			m_cColumnDesc, rgNewColumnDesc, 1, cons, IID_IRowset, 0, NULL, 
			&pTableID, NULL), S_OK))
	{
		CHECK(DropTableAndCheck(pTableID, m_pITDWC), S_OK);
		ReleaseDBID(pTableID, TRUE);
	}

CLEANUP:
	Table.DropTable();
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(11)
//*-----------------------------------------------------------------------
// @mfunc Primary key constraint on a column defined as primary key => DB_E_DUPLICATECONSTRAINTID
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCAddConstraint_PRIMARYKEY::Variation_11()
{ 
	TBEGIN
	HRESULT				hr;
	CTable				Table(m_pThisTestModule->m_pIUnknown2, (LPWSTR)gwszModuleName);
	DBCOLUMNDESC		*rgNewColumnDesc = NULL;
	DBID				*pTableID = NULL;
	CPrimaryKeyCons		cons;

	TESTC_PROVIDER(SettableProperty(DBPROP_COL_PRIMARYKEY, DBPROPSET_COLUMN, m_pIDBInitialize));

	// create a new table with a NULLABLE column
	DuplicateColumnDesc(m_rgColumnDesc, m_cColumnDesc, &rgNewColumnDesc);
	SetProperty(&rgNewColumnDesc[0].rgPropertySets, &rgNewColumnDesc[0].cPropertySets,
			DBPROP_COL_PRIMARYKEY, 
			VT_BOOL, (LPVOID)VARIANT_TRUE, 
			DBPROPOPTIONS_REQUIRED);
	SetProperty(&rgNewColumnDesc[0].rgPropertySets, &rgNewColumnDesc[0].cPropertySets,
			DBPROP_COL_NULLABLE, 
			VT_BOOL, (LPVOID)VARIANT_FALSE, 
			DBPROPOPTIONS_OPTIONAL);
	Table.SetColumnDesc(rgNewColumnDesc, m_cColumnDesc);
	Table.SetBuildColumnDesc(FALSE);
	
	TEST2C_(Table.CreateTable(0, 0), S_OK, DB_S_ERRORSOCCURRED);
	Table.AddInfoFromColumnsSchemaRowset(m_pITDWC, Table.GetTableName());

	// since there already is a primary key on this table
	// expect DB_E_DUPLICATECONSTRAINTID
	CHECK(AddPrimaryKeyConstraint(&Table, 1), DB_E_DUPLICATECONSTRAINTID);

	// try the same when creating a table
	cons.AddColumn(&rgNewColumnDesc[0].dbcid);
	if (!CHECK(hr = CreateAndCheckTableWithConstraints(m_pITDWC, NULL, NULL,
			m_cColumnDesc, rgNewColumnDesc, 1, cons, IID_IRowset, 0, NULL, 
			&pTableID, NULL), DB_E_DUPLICATECONSTRAINTID) && SUCCEEDED(hr))
	{
		CHECK(DropTableAndCheck(pTableID, m_pITDWC), S_OK);
		ReleaseDBID(pTableID, TRUE);
	}

CLEANUP:
	Table.DropTable();
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(12)
//*-----------------------------------------------------------------------
// @mfunc Primary key constraint on a column that already has a primary key constraint
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCAddConstraint_PRIMARYKEY::Variation_12()
{ 
	TBEGIN
	CTable				Table(m_pThisTestModule->m_pIUnknown2, (LPWSTR)gwszModuleName);
	CCol				col;
	CPrimaryKeyCons		cons;

	// create a base table without nullable columns
	TESTC_(CreateTableWithNoNullableColumns(&Table, 0), S_OK);

	// identify a nullable column
	TESTC_(Table.GetColInfo(1, col), S_OK);

	// alloc memory for column array
	cons.AddColumn(col.GetColID());
	TESTC_(AddConstraintAndCheck(m_pITDWC, &Table.GetTableID(), cons), S_OK);

	// another constraint ID
	CHECK(cons.MakeConstraintName(), S_OK);
	CHECK(AddConstraintAndCheck(m_pITDWC, &Table.GetTableID(), cons), DB_E_DUPLICATECONSTRAINTID);

CLEANUP:
	Table.DropTable();
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(13)
//*-----------------------------------------------------------------------
// @mfunc Primary key constraint on a column that is part of a foreign key constraint
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCAddConstraint_PRIMARYKEY::Variation_13()
{ 
	TBEGIN
	CTable					BaseTable(m_pThisTestModule->m_pIUnknown2, (LPWSTR)gwszModuleName);
	CTable					ReferencedTable(m_pThisTestModule->m_pIUnknown2, (LPWSTR)gwszModuleName);
	DBORDINAL				indexCol = 1;
	DBID					*pTableID = NULL;
	DBCOLUMNDESC			*rgNewColumnDesc = NULL;
	CPrimaryKeyCons			cons;
	CForeignKeyCons			consFK;
	CConsDescArray			consArray;
	CCol					col;

	DuplicateColumnDesc(m_rgColumnDesc, m_cColumnDesc, &rgNewColumnDesc);

	// create a base table without nullable columns and a reference table
	TESTC_(CreateTableWithNoNullableColumns(&BaseTable, 0), S_OK);
	TESTC_(ReferencedTable.CreateTable(0, 0), S_OK);
	ReferencedTable.AddInfoFromColumnsSchemaRowset(m_pITDWC, ReferencedTable.GetTableName());
	
	// select a column
	TESTC(BaseTable.CountColumnsOnTable() == ReferencedTable.CountColumnsOnTable())

	// prepare and add the unique constraint on the referenced table
	TESTC_(AddUniqueConstraint(&ReferencedTable, indexCol), S_OK);
	
	// build the foreign key constraint, use corresponding columns in tables
	CHECK(AddForeignKeyConstraint(&BaseTable, 1, &indexCol, 
		&ReferencedTable, 1, &indexCol, m_SupportedMatchType), S_OK);

	// add the PK constraint on the BaseTable
	CHECK(AddPrimaryKeyConstraint(&BaseTable, indexCol), S_OK);

	// try the same on a table -> create a PK and a FK, their column lists are not disjoint
	// add a first PK constraint
	TESTC_(ReferencedTable.GetColInfo(indexCol, col), S_OK);
	consFK.AddColumn(col.GetColID());
	consFK.AddForeignKeyColumn(&rgNewColumnDesc[indexCol-1].dbcid);
	consFK.SetReferencedTableID(&ReferencedTable.GetTableID());
	consArray.AddConsDesc(consFK);
	
	// add a second PK constraint
	cons.AddColumn(&rgNewColumnDesc[indexCol-1].dbcid);
	consArray.AddConsDesc(cons);

	if (CHECK(CreateAndCheckTableWithConstraints(m_pITDWC, NULL, NULL,
			m_cColumnDesc, rgNewColumnDesc, consArray, consArray, IID_IRowset, 0, NULL, 
			&pTableID, NULL), S_OK))
	{
		CHECK(DropTableAndCheck(pTableID, m_pITDWC), S_OK);
		ReleaseDBID(pTableID, TRUE);
	}
	
CLEANUP:
	ReleaseColumnDesc(rgNewColumnDesc, m_cColumnDesc, TRUE);
	BaseTable.DropTable();
	ReferencedTable.DropTable();
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(14)
//*-----------------------------------------------------------------------
// @mfunc Primary key constraint on a column that is part of an index
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCAddConstraint_PRIMARYKEY::Variation_14()
{ 
	TBEGIN
	CTable				Table(m_pThisTestModule->m_pIUnknown2, (LPWSTR)gwszModuleName);
	DBORDINAL			ulIndexCol = 1;

	// create a base table without nullable columns
	TESTC_(CreateTableWithNoNullableColumns(&Table, 0, ulIndexCol), S_OK);

	// add a PK constraint on the index column
	TESTC_(AddPrimaryKeyConstraint(&Table, ulIndexCol), S_OK);

CLEANUP:
	Table.DropTable();
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(15)
//*-----------------------------------------------------------------------
// @mfunc Primary key constraint on a column on a not empty table
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCAddConstraint_PRIMARYKEY::Variation_15()
{ 
	TBEGIN
	CTable				Table(m_pThisTestModule->m_pIUnknown2, (LPWSTR)gwszModuleName);

	// create a base table without nullable columns
	TESTC_(CreateTableWithNoNullableColumns(&Table, 10), S_OK);

	// add PK constraint
	TESTC_(AddPrimaryKeyConstraint(&Table, 1), S_OK);

CLEANUP:
	Table.DropTable();
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(16)
//*-----------------------------------------------------------------------
// @mfunc Primary key constraint on a column that already has duplicates (for the whole key)
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCAddConstraint_PRIMARYKEY::Variation_16()
{ 
	TBEGIN
	CTable				Table(m_pThisTestModule->m_pIUnknown2, (LPWSTR)gwszModuleName);

	// create a base table without nullable columns
	TESTC_(CreateTableWithNoNullableColumns(&Table, 10), S_OK);
	TESTC_(Table.Insert(7), S_OK);

	// expect DB_E_SCHEMAVIOLATION  because the table already contains duplicates
	TESTC_(AddPrimaryKeyConstraint(&Table, 1), DB_E_SCHEMAVIOLATION);

CLEANUP:
	Table.DropTable();
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(17)
//*-----------------------------------------------------------------------
// @mfunc Primary key constraint that has duplicates for a column in the key, but not for the whole key
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCAddConstraint_PRIMARYKEY::Variation_17()
{ 
	TBEGIN
	CTable					Table(m_pThisTestModule->m_pIUnknown2, (LPWSTR)gwszModuleName);
	CPrimaryKeyCons			cons;
	CCol					col;
	VARIANT					value;
	DBCOLUMNDESC			*rgNewColumnDesc = NULL;
	HRESULT					hr;
	CList<WCHAR *,WCHAR *>	NativeTypesList;
	CList<DBTYPE,DBTYPE>	ProviderTypesList;

	Table.CreateTypeColInfo(NativeTypesList, ProviderTypesList);
	// create a new table with a NULLABLE column
	DuplicateColumnDesc(m_rgColumnDesc, m_cColumnDesc, &rgNewColumnDesc);
	SetProperty(&rgNewColumnDesc[0].rgPropertySets, &rgNewColumnDesc[0].cPropertySets,
			DBPROP_COL_NULLABLE, 
			VT_BOOL, (LPVOID)VARIANT_FALSE, 
			DBPROPOPTIONS_REQUIRED);
	VariantInit(&value);
	GetDefaultValue(&rgNewColumnDesc[0], &value, &Table);
	SetDefaultProperty(&rgNewColumnDesc[0].rgPropertySets, &rgNewColumnDesc[0].cPropertySets,
				&value, DBPROPOPTIONS_REQUIRED);	// might be not supported
	VariantClear(&value);
	Table.SetColumnDesc(rgNewColumnDesc+1, m_cColumnDesc-1);
	Table.SetBuildColumnDesc(FALSE);
	SetProperty(&rgNewColumnDesc[1].rgPropertySets, &rgNewColumnDesc[1].cPropertySets,
			DBPROP_COL_NULLABLE, 
			VT_BOOL, (LPVOID)VARIANT_FALSE, 
			DBPROPOPTIONS_REQUIRED);
	
	TEST2C_(hr = Table.CreateTable(10, 0), S_OK, DB_S_ERRORSOCCURRED);
	Table.AddInfoFromColumnsSchemaRowset(m_pITDWC, Table.GetTableName());

	TEST2C_(hr = m_pITableDefinition->AddColumn(&Table.GetTableID(), 
		rgNewColumnDesc, NULL), S_OK, DB_E_ERRORSOCCURRED);
	TESTC(S_OK == hr);

	// identify a nullable column
	TESTC_(Table.GetColInfo(1, col), S_OK);

	// build the primary key
	cons.AddColumn(&rgNewColumnDesc[0].dbcid);
	cons.AddColumn(col.GetColID());

	TESTC_(AddConstraintAndCheck(m_pITDWC, &Table.GetTableID(), cons), S_OK);

CLEANUP:
	Table.SetColumnDesc(NULL, 0);
	ReleaseColumnDesc(rgNewColumnDesc, m_cColumnDesc);
	Table.DropTable();
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(18)
//*-----------------------------------------------------------------------
// @mfunc Abort retaining
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCAddConstraint_PRIMARYKEY::Variation_18()
{ 
	CAddPrimaryKeyConsTxnAdapter	TxnAdapter(this);
	CTransactionLocal				TxnLocal;

	return TxnLocal.DoTransactionTest(m_pITDWC, &TxnAdapter,
		TRUE,		// DDL
		TRUE,		// Abort
		TRUE		// Retaining
		);
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(19)
//*-----------------------------------------------------------------------
// @mfunc Abort non retaining
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCAddConstraint_PRIMARYKEY::Variation_19()
{ 
	CAddPrimaryKeyConsTxnAdapter	TxnAdapter(this);
	CTransactionLocal				TxnLocal;

	return TxnLocal.DoTransactionTest(m_pITDWC, &TxnAdapter,
		TRUE,		// DDL
		TRUE,		// Abort
		FALSE		// Non Retaining
		);
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(20)
//*-----------------------------------------------------------------------
// @mfunc Commit retaining
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCAddConstraint_PRIMARYKEY::Variation_20()
{ 
	CAddPrimaryKeyConsTxnAdapter	TxnAdapter(this);
	CTransactionLocal				TxnLocal;

	return TxnLocal.DoTransactionTest(m_pITDWC, &TxnAdapter,
		TRUE,		// DDL
		FALSE,		// Commit
		TRUE		// Retaining
		);
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(21)
//*-----------------------------------------------------------------------
// @mfunc Commit non retaining
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCAddConstraint_PRIMARYKEY::Variation_21()
{ 
	CAddPrimaryKeyConsTxnAdapter	TxnAdapter(this);
	CTransactionLocal				TxnLocal;

	return TxnLocal.DoTransactionTest(m_pITDWC, &TxnAdapter,
		TRUE,		// DDL
		FALSE,		// Commit
		FALSE		// Non Retaining
		);
} 
// }} TCW_VAR_PROTOTYPE_END

// {{ TCW_VAR_PROTOTYPE(22)
//*-----------------------------------------------------------------------
// @mfunc Create PK in a different catalog
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCAddConstraint_PRIMARYKEY::Variation_22()
{ 
	TBEGIN
	CTable					Table(m_pThisTestModule->m_pIUnknown2, (LPWSTR)gwszModuleName);
	CPrimaryKeyCons			cons;
	DBCONSTRAINTDESC		*pConsDesc = (DBCONSTRAINTDESC*)cons;
	CCol					col;
	DBORDINAL				indxCat = 0;
	CCatalogs				Catalogs(m_pIOpenRowset);
	IDBProperties			*pIDBProperties = NULL;
	CPropSets				PropSets;
	WCHAR					*pwszCurrentCatalog = NULL;
	WCHAR					*pwszQualTableName = NULL;
	WCHAR					*pwszCatalogName = NULL;
	WCHAR					*pwszSchemaName = NULL;

	TESTC_PROVIDER(SettableProperty(DBPROP_CURRENTCATALOG, DBPROPSET_DATASOURCE, m_pIDBInitialize));
	TESTC_PROVIDER(1 < Catalogs.cCatalogs());

	// create a table and an index
	TESTC_(CreateTableWithNoNullableColumns(&Table, 0), S_OK);
	Table.AddInfoFromColumnsSchemaRowset(m_pITDWC, Table.GetTableName());
	
	// select column
	TESTC_(Table.GetColInfo(1, col), S_OK);

	// set DBID of the table to its qualified form
	TESTC(DBKIND_NAME == Table.GetTableID().eKind);

	TESTC(GetCatalogSchemaNames(Table.GetTableName(), &pwszCatalogName, &pwszSchemaName));

	//Construct a fully Qualified TableName...
	TESTC_(m_pTable->GetQualifiedName(pwszCatalogName, pwszSchemaName, Table.GetTableName(), &pwszQualTableName),S_OK);
	Table.SetTableName(pwszQualTableName);

	// change the current catalog
	TESTC(GetProperty(DBPROP_CURRENTCATALOG, DBPROPSET_DATASOURCE, m_pIDBInitialize,
		&pwszCurrentCatalog));
	TESTC(NULL != pwszCurrentCatalog);

	TESTC(VerifyInterface(m_pIDBInitialize, IID_IDBProperties, DATASOURCE_INTERFACE, (IUnknown**)&pIDBProperties));

	if (0 == wcscmp(pwszCurrentCatalog, Catalogs[0]))
		indxCat++;

	CHECK(PropSets.AddProperty(DBPROP_CURRENTCATALOG, DBPROPSET_DATASOURCE, VT_BSTR, (LPVOID)Catalogs[indxCat]), S_OK);
	TESTC_PROVIDER(S_OK == pIDBProperties->SetProperties(PropSets, PropSets));

	// alloc memory for column array
	cons.AddColumn(col.GetColID());

	// try to make column unique
	TESTC_(AddConstraintAndCheck(m_pITDWC, &Table.GetTableID(), cons), S_OK);

CLEANUP:
	if (CHECK(PropSets.SetProperty(DBPROP_CURRENTCATALOG, DBPROPSET_DATASOURCE, VT_BSTR, (LPVOID)pwszCurrentCatalog), S_OK))
		CHECK(pIDBProperties->SetProperties(PropSets, PropSets), S_OK);

	SAFE_FREE(pwszCatalogName);
	SAFE_FREE(pwszSchemaName);
	SAFE_FREE(pwszQualTableName);
	SAFE_FREE(pwszCurrentCatalog);
	SAFE_RELEASE(pIDBProperties);
	Table.DropTable();
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END

int TCAddConstraint_PRIMARYKEY::Variation_23() {
	TBEGIN
	
	CLimitTable		Table;

	TESTC_(Table.CheckPrimaryKeyLimit(), S_OK);

CLEANUP:
	TRETURN;
}



// {{ TCW_TERMINATE_METHOD
//*-----------------------------------------------------------------------
// @mfunc TestCase Termination Routine 
//
// @rdesc TEST_PASS or TEST_FAIL 
//
BOOL TCAddConstraint_PRIMARYKEY::Terminate()
{ 
	// TO DO:  Add your own code here 

// {{ TCW_TERM_BASECLASS_CHECK2
	return(TCITableDefinition::Terminate());
} 	// }}
// }} TCW_TERMINATE_METHOD_END
// }} TCW_TC_PROTOTYPE_END


// {{ TCW_TC_PROTOTYPE(TCAddConstraint_FOREIGNKEY)
//*-----------------------------------------------------------------------
//| Test Case:		TCAddConstraint_FOREIGNKEY - Testcase for ITableDefinitionWithConstraints::AddConstraint used with DBCONSTRAINTTYPE_FOREIGNKEY
//| Created:  	7/29/99
//*-----------------------------------------------------------------------

//*-----------------------------------------------------------------------
// @mfunc TestCase Initialization Routine
//
// @rdesc TRUE or FALSE
//
BOOL TCAddConstraint_FOREIGNKEY::Init()
{ 
	m_pReferenceTable = NULL;
	// {{ TCW_INIT_BASECLASS_CHECK
	if(TCITableDefinition::Init())
	// }}
	{ 
		if (m_pITDWC==NULL)
		{
			odtLog << "ITableDefinitionWithConstraints is not supported.\n";
			return TEST_SKIPPED;
		}

		m_pReferenceTable = new CTable(m_pThisTestModule->m_pIUnknown2, (LPWSTR)gwszModuleName);
		TESTC_(m_pReferenceTable->CreateTable(0, 1), S_OK);
		m_pReferenceTable->AddInfoFromColumnsSchemaRowset(m_pITDWC, m_pReferenceTable->GetTableName());
		return TRUE;
	} 
CLEANUP:
	return FALSE;
} 




// {{ TCW_VAR_PROTOTYPE(1)
//*-----------------------------------------------------------------------
// @mfunc Simple foreign key constraint
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCAddConstraint_FOREIGNKEY::Variation_1()
{ 
	TBEGIN
	CTable					Table(m_pThisTestModule->m_pIUnknown2, (LPWSTR)gwszModuleName);
	CCol					col, col2;
	DBORDINAL				indexCol = 1;
	CForeignKeyCons			cons(NULL, m_SupportedMatchType);
	DBCOLUMNDESC			*rgNewColumnDesc	= NULL;
	DBID					*pTableID			= NULL;

	TESTC_(Table.CreateTable(0, 0), S_OK);
	
	// select columns from tables
	Table.AddInfoFromColumnsSchemaRowset(m_pITDWC, Table.GetTableName());
	Table.BuildColumnDescs(&rgNewColumnDesc);

	TESTC(Table.CountColumnsOnTable() == m_pReferenceTable->CountColumnsOnTable())
	TESTC_(Table.GetColInfo(indexCol, col), S_OK);
	TESTC_(m_pReferenceTable->GetColInfo(indexCol, col2), S_OK);

	// build the foreign key constraint, use corresponding columns in tables
	cons.AddColumn(col2.GetColID());
	cons.AddForeignKeyColumn(col.GetColID());
	cons.SetReferencedTableID(&m_pReferenceTable->GetTableID());

	// add the foreign key constraint
	CHECK(AddConstraintAndCheck(m_pITDWC, &Table.GetTableID(), cons), S_OK);

	// try the same when creating a table
	TESTC_(cons.MakeConstraintName(), S_OK);
	if (CHECK(CreateAndCheckTableWithConstraints(m_pITDWC, NULL, NULL,
			m_cColumnDesc, rgNewColumnDesc, 1, cons, IID_IRowset, 0, NULL, 
			&pTableID, NULL), S_OK))
	{
		CHECK(DropTableAndCheck(pTableID, m_pITDWC), S_OK);
		ReleaseDBID(pTableID, TRUE);
	}

CLEANUP:
	ReleaseColumnDesc(rgNewColumnDesc, m_cColumnDesc, TRUE);
	Table.DropTable();
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END





// {{ TCW_VAR_PROTOTYPE(2)
//*-----------------------------------------------------------------------
// @mfunc Foregin key is made of several columns
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCAddConstraint_FOREIGNKEY::Variation_2()
{ 
	TBEGIN
	CTable					BaseTable(m_pThisTestModule->m_pIUnknown2, (LPWSTR)gwszModuleName);
	CTable					RefTable(m_pThisTestModule->m_pIUnknown2, (LPWSTR)gwszModuleName);
	DBORDINAL				rgCol[] = {1, 2};
	CForeignKeyCons			cons(NULL, m_SupportedMatchType);
	DBCOLUMNDESC			*rgNewColumnDesc	= NULL;
	DBID					*pTableID			= NULL;
	CCol					col;
	DBORDINAL				index;

	// create a new table with a NOT NULLABLE column
	DuplicateColumnDesc(m_rgColumnDesc, m_cColumnDesc, &rgNewColumnDesc);

	TESTC_(BaseTable.CreateTable(0, 0), S_OK);
	BaseTable.AddInfoFromColumnsSchemaRowset(m_pITDWC, BaseTable.GetTableName());
	TESTC_(RefTable.CreateTable(0, 0), S_OK);
	RefTable.AddInfoFromColumnsSchemaRowset(m_pITDWC, RefTable.GetTableName());
	
	// select a column
	TESTC(BaseTable.CountColumnsOnTable() == RefTable.CountColumnsOnTable())

	// make the referenced columns unique
	TESTC_(AddUniqueConstraint(&RefTable, NUMELEM(rgCol), rgCol), S_OK);

	// add the foreign key constraint
	CHECK(AddForeignKeyConstraint(&BaseTable, NUMELEM(rgCol), rgCol,
		&RefTable, NUMELEM(rgCol), rgCol, m_SupportedMatchType), S_OK);

	// try the same when creating a table
	for (index=0; index < NUMELEM(rgCol); index++)
	{
		TESTC_(RefTable.GetColInfo(rgCol[index], col), S_OK);
		cons.AddColumn(col.GetColID());
		cons.AddForeignKeyColumn(&rgNewColumnDesc[rgCol[index]-1].dbcid);
	}
	cons.SetReferencedTableID(&RefTable.GetTableID());

	if (CHECK(CreateAndCheckTableWithConstraints(m_pITDWC, NULL, NULL,
			m_cColumnDesc, rgNewColumnDesc, 1, cons, IID_IRowset, 0, NULL, 
			&pTableID, NULL), S_OK))
	{
		CHECK(DropTableAndCheck(pTableID, m_pITDWC), S_OK);
		ReleaseDBID(pTableID, TRUE);
	}

CLEANUP:
	ReleaseColumnDesc(rgNewColumnDesc, m_cColumnDesc, TRUE);
	BaseTable.DropTable();
	RefTable.DropTable();
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(3)
//*-----------------------------------------------------------------------
// @mfunc Multiple foreign key constraints on a table
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCAddConstraint_FOREIGNKEY::Variation_3()
{ 
	TBEGIN
	CTable					BaseTable(m_pThisTestModule->m_pIUnknown2, (LPWSTR)gwszModuleName);
	CTable					RefTable(m_pThisTestModule->m_pIUnknown2, (LPWSTR)gwszModuleName);
	DBORDINAL				rgCol[] = {1, 2};
	DBORDINAL				rgCol2[] = {3, 4};
	DBCOLUMNDESC			*rgNewColumnDesc	= NULL;
	DBID					*pTableID			= NULL;
	CForeignKeyCons			cons(NULL, m_SupportedMatchType);
	CConsDescArray			consArray;
	CCol					col;

	// create a new table with a NOT NULLABLE column
	DuplicateColumnDesc(m_rgColumnDesc, m_cColumnDesc, &rgNewColumnDesc);

	TESTC_(BaseTable.CreateTable(0, 0), S_OK);
	BaseTable.AddInfoFromColumnsSchemaRowset(m_pITDWC, BaseTable.GetTableName());
	TESTC_(RefTable.CreateTable(0, 0), S_OK);
	RefTable.AddInfoFromColumnsSchemaRowset(m_pITDWC, RefTable.GetTableName());
	
	// select a column
	TESTC(BaseTable.CountColumnsOnTable() == RefTable.CountColumnsOnTable())

	// make the referenced columns unique
	TESTC_(AddUniqueConstraint(&RefTable, NUMELEM(rgCol), rgCol), S_OK);
	TESTC_(AddUniqueConstraint(&RefTable, NUMELEM(rgCol2), rgCol2), S_OK);

	// add the foreign key constraint
	TESTC_(AddForeignKeyConstraint(&BaseTable, NUMELEM(rgCol), rgCol,
		&RefTable, NUMELEM(rgCol), rgCol, m_SupportedMatchType), S_OK);

	// set a second foreign constraint
	CHECK(AddForeignKeyConstraint(&BaseTable, NUMELEM(rgCol2), rgCol2,
		&RefTable, NUMELEM(rgCol2), rgCol2, m_SupportedMatchType), S_OK);

	// try to create a table with 2 disjoint FK constraint
	TESTC_(RefTable.GetColInfo(rgCol[0], col), S_OK);
	cons.AddColumn(col.GetColID());
	TESTC_(RefTable.GetColInfo(rgCol[1], col), S_OK);
	cons.AddColumn(col.GetColID());
	cons.AddForeignKeyColumn(&rgNewColumnDesc[rgCol[0]-1].dbcid);
	cons.AddForeignKeyColumn(&rgNewColumnDesc[rgCol[1]-1].dbcid);
	cons.SetReferencedTableID(&RefTable.GetTableID());
	consArray.AddConsDesc(cons);

	TESTC_(cons.MakeConstraintName(), S_OK);
	CHECK(cons.ReleaseColumnList(), S_OK);
	CHECK(cons.ReleaseForeignKeyColumnList(), S_OK);
	TESTC_(RefTable.GetColInfo(rgCol2[0], col), S_OK);
	cons.AddColumn(col.GetColID());
	TESTC_(RefTable.GetColInfo(rgCol2[1], col), S_OK);
	cons.AddColumn(col.GetColID());
	cons.AddForeignKeyColumn(&rgNewColumnDesc[rgCol2[0]-1].dbcid);
	cons.AddForeignKeyColumn(&rgNewColumnDesc[rgCol2[1]-1].dbcid);
	consArray.AddConsDesc(cons);

	if (CHECK(CreateAndCheckTableWithConstraints(m_pITDWC, NULL, NULL,
			m_cColumnDesc, rgNewColumnDesc, consArray, consArray, IID_IRowset, 0, NULL, 
			&pTableID, NULL), S_OK))
	{
		CHECK(DropTableAndCheck(pTableID, m_pITDWC), S_OK);
		ReleaseDBID(pTableID, TRUE);
	}

CLEANUP:
	ReleaseColumnDesc(rgNewColumnDesc, m_cColumnDesc, TRUE);
	BaseTable.DropTable();
	RefTable.DropTable();
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(4)
//*-----------------------------------------------------------------------
// @mfunc Multiple overlapping foreign key constraints
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCAddConstraint_FOREIGNKEY::Variation_4()
{ 
	TBEGIN
	CTable					BaseTable(m_pThisTestModule->m_pIUnknown2, (LPWSTR)gwszModuleName);
	CTable					RefTable(m_pThisTestModule->m_pIUnknown2, (LPWSTR)gwszModuleName);
	DBORDINAL				rgCol[] = {1, 2};
	DBORDINAL				rgCol2[] = {3, 2};
	DBCOLUMNDESC			*rgNewColumnDesc	= NULL;
	DBID					*pTableID			= NULL;
	CForeignKeyCons			cons(NULL, m_SupportedMatchType);
	CConsDescArray			consArray;
	CCol					col;

	// create a new table with a NOT NULLABLE column
	DuplicateColumnDesc(m_rgColumnDesc, m_cColumnDesc, &rgNewColumnDesc);

	TESTC_(BaseTable.CreateTable(0, 0), S_OK);
	BaseTable.AddInfoFromColumnsSchemaRowset(m_pITDWC, BaseTable.GetTableName());
	TESTC_(RefTable.CreateTable(0, 0), S_OK);
	RefTable.AddInfoFromColumnsSchemaRowset(m_pITDWC, RefTable.GetTableName());
	
	// select a column
	TESTC(BaseTable.CountColumnsOnTable() == RefTable.CountColumnsOnTable())

	// make the referenced columns unique
	TESTC_(AddUniqueConstraint(&RefTable, NUMELEM(rgCol), rgCol), S_OK);
	TESTC_(AddUniqueConstraint(&RefTable, NUMELEM(rgCol2), rgCol2), S_OK);

	// add the foreign key constraint
	TESTC_(AddForeignKeyConstraint(&BaseTable, NUMELEM(rgCol), rgCol,
		&RefTable, NUMELEM(rgCol), rgCol, m_SupportedMatchType), S_OK);

	// set a second foreign constraint
	TESTC_(AddForeignKeyConstraint(&BaseTable, NUMELEM(rgCol2), rgCol2,
		&RefTable, NUMELEM(rgCol2), rgCol2, m_SupportedMatchType), S_OK);

	// try to create a table with 2 overlapping FK constraint
	TESTC_(RefTable.GetColInfo(rgCol[0], col), S_OK);
	cons.AddColumn(col.GetColID());
	TESTC_(RefTable.GetColInfo(rgCol[1], col), S_OK);
	cons.AddColumn(col.GetColID());
	cons.AddForeignKeyColumn(&rgNewColumnDesc[rgCol[0]-1].dbcid);
	cons.AddForeignKeyColumn(&rgNewColumnDesc[rgCol[1]-1].dbcid);
	cons.SetReferencedTableID(&RefTable.GetTableID());
	consArray.AddConsDesc(cons);

	TESTC_(cons.MakeConstraintName(), S_OK);
	CHECK(cons.ReleaseColumnList(), S_OK);
	CHECK(cons.ReleaseForeignKeyColumnList(), S_OK);
	TESTC_(RefTable.GetColInfo(rgCol2[0], col), S_OK);
	cons.AddColumn(col.GetColID());
	TESTC_(RefTable.GetColInfo(rgCol2[1], col), S_OK);
	cons.AddColumn(col.GetColID());
	cons.AddForeignKeyColumn(&rgNewColumnDesc[rgCol2[0]-1].dbcid);
	cons.AddForeignKeyColumn(&rgNewColumnDesc[rgCol2[1]-1].dbcid);
	consArray.AddConsDesc(cons);

	if (CHECK(CreateAndCheckTableWithConstraints(m_pITDWC, NULL, NULL,
			m_cColumnDesc, rgNewColumnDesc, consArray, consArray, IID_IRowset, 0, NULL, 
			&pTableID, NULL), S_OK))
	{
		CHECK(DropTableAndCheck(pTableID, m_pITDWC), S_OK);
		ReleaseDBID(pTableID, TRUE);
	}

CLEANUP:
	ReleaseColumnDesc(rgNewColumnDesc, m_cColumnDesc, TRUE);
	BaseTable.DropTable();
	RefTable.DropTable();
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(5)
//*-----------------------------------------------------------------------
// @mfunc Create a foreign key on each column of the table
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCAddConstraint_FOREIGNKEY::Variation_5()
{ 
	TBEGIN
	CTable					BaseTable(m_pThisTestModule->m_pIUnknown2, (LPWSTR)gwszModuleName);
	CTable					RefTable(m_pThisTestModule->m_pIUnknown2, (LPWSTR)gwszModuleName);
	CCol					col;
	CForeignKeyCons			cons(NULL, m_SupportedMatchType);
	DBORDINAL				indexCol;
	DBCOLUMNDESC			*rgNewColumnDesc	= NULL;
	DBID					*pTableID			= NULL;

	// create a new table with a NOT NULLABLE column
	TESTC_(BaseTable.CreateTable(0, 0), S_OK);
	BaseTable.AddInfoFromColumnsSchemaRowset(m_pITDWC, BaseTable.GetTableName());
	BaseTable.BuildColumnDescs(&rgNewColumnDesc);	

	TESTC_(RefTable.CreateTable(0, 0), S_OK);
	RefTable.AddInfoFromColumnsSchemaRowset(m_pITDWC, RefTable.GetTableName());
	
	// select a column
	TESTC(BaseTable.CountColumnsOnTable() == RefTable.CountColumnsOnTable())

	// set referenced table
	cons.SetReferencedTableID(&RefTable.GetTableID());

	// make room for columns id
	for (indexCol = 1; indexCol <= BaseTable.CountColumnsOnTable(); indexCol++)
	{
		if (!CHECK(BaseTable.GetColInfo(indexCol, col), S_OK))
			continue;

		odtLog << col.GetProviderTypeName() << "\n";

		// make the referenced columns unique
		if (S_OK != AddUniqueConstraint(&RefTable, indexCol))
			continue;

		// build the foreign key constraint, use corresponding columns in tables
		// set column on base table
		cons.ReleaseForeignKeyColumnList();
		cons.AddForeignKeyColumn(col.GetColID());

		// set foreign column
		if (!CHECK(RefTable.GetColInfo(indexCol, col), S_OK))
			continue;
		cons.ReleaseColumnList();
		cons.AddColumn(col.GetColID());

		// add the foreign key constraint
		if (CHECK(AddConstraintAndCheck(m_pITDWC, &BaseTable.GetTableID(), cons), S_OK))
		{
			// drop the constraint
			CHECK(DropConstraintAndCheck(m_pITDWC, &BaseTable.GetTableID(), cons), S_OK);
		}

		// try the same when creating a table
		TESTC_(cons.MakeConstraintName(), S_OK);
		if (CHECK(CreateAndCheckTableWithConstraints(m_pITDWC, NULL, NULL,
				m_cColumnDesc, rgNewColumnDesc, 1, cons, IID_IRowset, 0, NULL, 
				&pTableID, NULL), S_OK))
		{
			CHECK(DropTableAndCheck(pTableID, m_pITDWC), S_OK);
			ReleaseDBID(pTableID, TRUE);
		}
	}

CLEANUP:
	ReleaseColumnDesc(rgNewColumnDesc, m_cColumnDesc, TRUE);
	BaseTable.DropTable();
	RefTable.DropTable();
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(6)
//*-----------------------------------------------------------------------
// @mfunc Create a foreign key on all columns
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCAddConstraint_FOREIGNKEY::Variation_6()
{ 
	TBEGIN
	CTable					BaseTable(m_pThisTestModule->m_pIUnknown2, (LPWSTR)gwszModuleName);
	CTable					RefTable(m_pThisTestModule->m_pIUnknown2, (LPWSTR)gwszModuleName);
	CCol					col;
	CForeignKeyCons			cons(NULL, m_SupportedMatchType);
	DBORDINAL				indexCol;
	CUniqueCons				consUnique;
	ULONG_PTR				uMaxColsInIndex = 0,
							uAdded = 0,
							uMaxIndexSize = 0,
							uCurIndexSize = 0,
							uColSizeInBytes = 0;

	TESTC_(BaseTable.CreateTable(0, 0), S_OK);
	BaseTable.AddInfoFromColumnsSchemaRowset(m_pITDWC, BaseTable.GetTableName());
	TESTC_(RefTable.CreateTable(0, 0), S_OK);
	RefTable.AddInfoFromColumnsSchemaRowset(m_pITDWC, RefTable.GetTableName());
	
	// select a column
	TESTC(BaseTable.CountColumnsOnTable() == RefTable.CountColumnsOnTable())

	// set referenced table
	cons.SetReferencedTableID(&RefTable.GetTableID());

	if (SupportedProperty(DBPROP_MAXINDEXSIZE, DBPROPSET_DATASOURCEINFO, GetModInfo()->GetThisTestModule()->m_pIUnknown, DATASOURCE_INTERFACE))
		TESTC(GetProperty(DBPROP_MAXINDEXSIZE, DBPROPSET_DATASOURCEINFO, GetModInfo()->GetThisTestModule()->m_pIUnknown, &uMaxIndexSize));

	for (indexCol = 1; indexCol <= BaseTable.CountColumnsOnTable(); indexCol++)
	{
		// set column on base table
		TESTC_(BaseTable.GetColInfo(indexCol, col), S_OK);

		// Note: col.GetColumnSize returns length for string data types and we need size in bytes
		//			so multiply ColumnSize by 2 for WSTR
		if(col.GetIsFixedLength() )
			uColSizeInBytes = col.GetColumnSize() * (col.GetProviderType()==DBTYPE_WSTR ? 2:1);
		else
			uColSizeInBytes = 0;


		if (uMaxIndexSize && (uMaxIndexSize - uCurIndexSize) < uColSizeInBytes)
			continue;

		cons.AddForeignKeyColumn(col.GetColID());

		// set foreign column
		TESTC_(RefTable.GetColInfo(indexCol, col), S_OK);
		cons.AddColumn(col.GetColID());
		consUnique.AddColumn(col.GetColID());

		uAdded++;
		uCurIndexSize += uColSizeInBytes;

		if (uMaxColsInIndex && uAdded == uMaxColsInIndex)
			break;
	}

	// make the referenced columns unique
	TESTC_(AddConstraintAndCheck(m_pITDWC, &RefTable.GetTableID(), consUnique), S_OK);

	// add the foreign key constraint
	TESTC_(AddConstraintAndCheck(m_pITDWC, &BaseTable.GetTableID(), cons), S_OK);

CLEANUP:
	BaseTable.DropTable();
	RefTable.DropTable();
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(7)
//*-----------------------------------------------------------------------
// @mfunc Create foreign key and try to drop the reference table
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCAddConstraint_FOREIGNKEY::Variation_7()
{ 
	TBEGIN
	CTable					BaseTable(m_pThisTestModule->m_pIUnknown2, (LPWSTR)gwszModuleName);
	CTable					RefTable(m_pThisTestModule->m_pIUnknown2, (LPWSTR)gwszModuleName);
	CForeignKeyCons			cons(NULL, m_SupportedMatchType);
	CCol					col;
	DBORDINAL				rgCol[] = {1};

	TESTC_(BaseTable.CreateTable(0, 0), S_OK);
	BaseTable.AddInfoFromColumnsSchemaRowset(m_pITDWC, BaseTable.GetTableName());
	TESTC_(RefTable.CreateTable(0, 0), S_OK);
	RefTable.AddInfoFromColumnsSchemaRowset(m_pITDWC, RefTable.GetTableName());
	
	// select a column
	TESTC(BaseTable.CountColumnsOnTable() == RefTable.CountColumnsOnTable())

	// make the referenced columns unique
	TESTC_(AddUniqueConstraint(&RefTable, NUMELEM(rgCol), rgCol), S_OK);

	// add the foreign key constraint
	TESTC_(AddForeignKeyConstraint(&BaseTable, NUMELEM(rgCol), rgCol, 
		&RefTable, NUMELEM(rgCol), rgCol, m_SupportedMatchType), S_OK);

	// try to drop the table or a column in the FK constraint
	TESTC_PROVIDER(S_OK == RefTable.GetColInfo(rgCol[0], col));
	CHECK(DropTableAndCheck(&RefTable.GetTableID()), DB_E_DROPRESTRICTED);
	CHECK(DropColumnAndCheck(&RefTable.GetTableID(), col.GetColID()), DB_E_DROPRESTRICTED);

CLEANUP:
	BaseTable.DropTable();
	RefTable.DropTable();
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(8)
//*-----------------------------------------------------------------------
// @mfunc On a nullable column
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCAddConstraint_FOREIGNKEY::Variation_8()
{ 
	TBEGIN
	DBORDINAL			rgCol[] = {1};
	DBCOLUMNDESC		*rgNewColumnDesc = NULL;
	CTable				BaseTable(m_pThisTestModule->m_pIUnknown2, (LPWSTR)gwszModuleName);
	CTable				RefTable(m_pThisTestModule->m_pIUnknown2, (LPWSTR)gwszModuleName);
	DBID				*pTableID = NULL;
	CForeignKeyCons		cons;
	CCol				col;

	DuplicateColumnDesc(m_rgColumnDesc, m_cColumnDesc, &rgNewColumnDesc);
	SetProperty(&rgNewColumnDesc[rgCol[0]-1].rgPropertySets, &rgNewColumnDesc[rgCol[0]-1].cPropertySets,
			DBPROP_COL_NULLABLE, 
			VT_BOOL, (LPVOID)VARIANT_TRUE, 
			DBPROPOPTIONS_REQUIRED);
	BaseTable.SetColumnDesc(rgNewColumnDesc, m_cColumnDesc);
	BaseTable.SetBuildColumnDesc(FALSE);
	
	TESTC_(BaseTable.CreateTable(0, 0), S_OK);
	BaseTable.AddInfoFromColumnsSchemaRowset(m_pITDWC, BaseTable.GetTableName());
	TESTC_(RefTable.CreateTable(0, 0), S_OK);
	RefTable.AddInfoFromColumnsSchemaRowset(m_pITDWC, RefTable.GetTableName());

	// make the referenced columns unique
	TESTC_(AddUniqueConstraint(&RefTable, NUMELEM(rgCol), rgCol), S_OK);

	// add the FK constraint on the NULLABLE column
	CHECK(AddForeignKeyConstraint(&BaseTable, NUMELEM(rgCol), rgCol,
		&RefTable, NUMELEM(rgCol), rgCol, m_SupportedMatchType), S_OK);

	// try the same when creating a table
	cons.SetReferencedTableID(&RefTable.GetTableID());
	cons.AddForeignKeyColumn(&rgNewColumnDesc[rgCol[0]-1].dbcid);
	TESTC_(RefTable.GetColInfo(rgCol[0], col), S_OK);
	cons.AddColumn(col.GetColID());
	TESTC_(cons.MakeConstraintName(), S_OK);
	if (CHECK(CreateAndCheckTableWithConstraints(m_pITDWC, NULL, NULL,
			m_cColumnDesc, rgNewColumnDesc, 1, cons, IID_IRowset, 0, NULL, 
			&pTableID, NULL), S_OK))
	{
		CHECK(DropTableAndCheck(pTableID, m_pITDWC), S_OK);
		ReleaseDBID(pTableID, TRUE);
	}

CLEANUP:
	BaseTable.DropTable();
	RefTable.DropTable();
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(9)
//*-----------------------------------------------------------------------
// @mfunc On a not nullable column
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCAddConstraint_FOREIGNKEY::Variation_9()
{ 
	TBEGIN
	DBORDINAL			rgCol[] = {1};
	DBCOLUMNDESC		*rgNewColumnDesc = NULL;
	CTable				BaseTable(m_pThisTestModule->m_pIUnknown2, (LPWSTR)gwszModuleName);
	CTable				RefTable(m_pThisTestModule->m_pIUnknown2, (LPWSTR)gwszModuleName);
	DBID				*pTableID = NULL;
	CForeignKeyCons		cons;
	CCol				col;

	// create a new table with a NOT NULLABLE column
	DuplicateColumnDesc(m_rgColumnDesc, m_cColumnDesc, &rgNewColumnDesc);
	SetProperty(&rgNewColumnDesc[rgCol[0]-1].rgPropertySets, &rgNewColumnDesc[rgCol[0]-1].cPropertySets,
			DBPROP_COL_NULLABLE, 
			VT_BOOL, (LPVOID)VARIANT_FALSE, 
			DBPROPOPTIONS_REQUIRED);
	BaseTable.SetColumnDesc(rgNewColumnDesc, m_cColumnDesc);
	BaseTable.SetBuildColumnDesc(FALSE);
	
	TESTC_(BaseTable.CreateTable(0, 0), S_OK);
	BaseTable.AddInfoFromColumnsSchemaRowset(m_pITDWC, BaseTable.GetTableName());
	TESTC_(RefTable.CreateTable(0, 0), S_OK);
	RefTable.AddInfoFromColumnsSchemaRowset(m_pITDWC, RefTable.GetTableName());

	// make the referenced columns unique
	TESTC_(AddUniqueConstraint(&RefTable, NUMELEM(rgCol), rgCol), S_OK);

	// add the FK constraint on the not NULLABLE column
	CHECK(AddForeignKeyConstraint(&BaseTable, NUMELEM(rgCol), rgCol,
		&RefTable, NUMELEM(rgCol), rgCol, m_SupportedMatchType), S_OK);

	// try the same when creating a table
	cons.SetReferencedTableID(&RefTable.GetTableID());
	cons.AddForeignKeyColumn(&rgNewColumnDesc[rgCol[0]-1].dbcid);
	TESTC_(RefTable.GetColInfo(rgCol[0], col), S_OK);
	cons.AddColumn(col.GetColID());
	TESTC_(cons.MakeConstraintName(), S_OK);
	if (CHECK(CreateAndCheckTableWithConstraints(m_pITDWC, NULL, NULL,
			m_cColumnDesc, rgNewColumnDesc, 1, cons, IID_IRowset, 0, NULL, 
			&pTableID, NULL), S_OK))
	{
		CHECK(DropTableAndCheck(pTableID, m_pITDWC), S_OK);
		ReleaseDBID(pTableID, TRUE);
	}

CLEANUP:
	BaseTable.DropTable();
	RefTable.DropTable();
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(10)
//*-----------------------------------------------------------------------
// @mfunc On a column having a default value
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCAddConstraint_FOREIGNKEY::Variation_10()
{ 
	TBEGIN
	VARIANT					value;
	DBORDINAL				rgCol[] = {1};
	DBCOLUMNDESC			*rgNewColumnDesc = NULL;
	CTable					BaseTable(m_pThisTestModule->m_pIUnknown2, (LPWSTR)gwszModuleName);
	CTable					RefTable(m_pThisTestModule->m_pIUnknown2, (LPWSTR)gwszModuleName);
	CList<WCHAR *,WCHAR *>	NativeTypesList;
	CList<DBTYPE,DBTYPE>	ProviderTypesList;
	DBID					*pTableID = NULL;
	CForeignKeyCons			cons;
	CCol					col;

	BaseTable.CreateTypeColInfo(NativeTypesList, ProviderTypesList);
	// create a new table with a NOT NULLABLE column
	DuplicateColumnDesc(m_rgColumnDesc, m_cColumnDesc, &rgNewColumnDesc);
	VariantInit(&value);
	GetDefaultValue(&rgNewColumnDesc[rgCol[0]-1], &value, &BaseTable);
	SetDefaultProperty(&rgNewColumnDesc[rgCol[0]-1].rgPropertySets, &rgNewColumnDesc[rgCol[0]-1].cPropertySets,
				&value, DBPROPOPTIONS_REQUIRED);	// might be not supported
	VariantClear(&value);
	BaseTable.SetColumnDesc(rgNewColumnDesc, m_cColumnDesc);
	BaseTable.SetBuildColumnDesc(FALSE);
	
	TESTC_(BaseTable.CreateTable(0, 0), S_OK);
	BaseTable.AddInfoFromColumnsSchemaRowset(m_pITDWC, BaseTable.GetTableName());
	TESTC_(RefTable.CreateTable(0, 0), S_OK);
	RefTable.AddInfoFromColumnsSchemaRowset(m_pITDWC, RefTable.GetTableName());

	// make the referenced columns unique
	TESTC_(AddUniqueConstraint(&RefTable, NUMELEM(rgCol), rgCol), S_OK);

	// add the FK constraint
	CHECK(AddForeignKeyConstraint(&BaseTable, NUMELEM(rgCol), rgCol,
		&RefTable, NUMELEM(rgCol), rgCol, m_SupportedMatchType), S_OK);

	// try the same when creating a table
	cons.SetReferencedTableID(&RefTable.GetTableID());
	cons.AddForeignKeyColumn(&rgNewColumnDesc[rgCol[0]-1].dbcid);
	TESTC_(RefTable.GetColInfo(rgCol[0], col), S_OK);
	cons.AddColumn(col.GetColID());
	TESTC_(cons.MakeConstraintName(), S_OK);
	if (CHECK(CreateAndCheckTableWithConstraints(m_pITDWC, NULL, NULL,
			m_cColumnDesc, rgNewColumnDesc, 1, cons, IID_IRowset, 0, NULL, 
			&pTableID, NULL), S_OK))
	{
		CHECK(DropTableAndCheck(pTableID, m_pITDWC), S_OK);
		ReleaseDBID(pTableID, TRUE);
	}

CLEANUP:
	BaseTable.DropTable();
	RefTable.DropTable();
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(11)
//*-----------------------------------------------------------------------
// @mfunc On a column defined as unique
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCAddConstraint_FOREIGNKEY::Variation_11()
{ 
	TBEGIN
	CTable					BaseTable(m_pThisTestModule->m_pIUnknown2, (LPWSTR)gwszModuleName);
	CTable					RefTable(m_pThisTestModule->m_pIUnknown2, (LPWSTR)gwszModuleName);
	DBORDINAL				rgCol[] = {1};
	DBCOLUMNDESC			*rgNewColumnDesc	= NULL;
	DBID					*pTableID			= NULL;
	CForeignKeyCons			consFK;
	CUniqueCons				cons;
	CCol					col, col2;
	CConsDescArray			consArray;

	TESTC_(BaseTable.CreateTable(0, 0), S_OK);
	BaseTable.AddInfoFromColumnsSchemaRowset(m_pITDWC, BaseTable.GetTableName());
	BaseTable.BuildColumnDescs(&rgNewColumnDesc);

	TESTC_(RefTable.CreateTable(0, 0), S_OK);
	RefTable.AddInfoFromColumnsSchemaRowset(m_pITDWC, RefTable.GetTableName());
	
	// select a column
	TESTC(BaseTable.CountColumnsOnTable() == RefTable.CountColumnsOnTable())

	// make the referenced columns unique
	TESTC_(AddUniqueConstraint(&RefTable, NUMELEM(rgCol), rgCol), S_OK);

	// make the base column unique
	TESTC_(AddUniqueConstraint(&BaseTable, NUMELEM(rgCol), rgCol), S_OK);

	// add the FK constraint
	TESTC_(AddForeignKeyConstraint(&BaseTable, NUMELEM(rgCol), rgCol,
		&RefTable, NUMELEM(rgCol), rgCol, m_SupportedMatchType), S_OK);

	// try to create a table with a unique and a FK cons
	TESTC_(RefTable.GetColInfo(rgCol[0], col), S_OK);
	TESTC_(BaseTable.GetColInfo(rgCol[0], col2), S_OK);
	cons.AddColumn(col2.GetColID());
	consArray.AddConsDesc(cons);

	consFK.SetReferencedTableID(&RefTable.GetTableID());
	consFK.AddForeignKeyColumn(col2.GetColID());
	consFK.AddColumn(col.GetColID());
	consArray.AddConsDesc(consFK);

	TESTC_(cons.MakeConstraintName(), S_OK);
	if (CHECK(CreateAndCheckTableWithConstraints(m_pITDWC, NULL, NULL,
			m_cColumnDesc, rgNewColumnDesc, consArray, consArray, IID_IRowset, 0, NULL, 
			&pTableID, NULL), S_OK))
	{
		CHECK(DropTableAndCheck(pTableID, m_pITDWC), S_OK);
		ReleaseDBID(pTableID, TRUE);
	}

CLEANUP:
	ReleaseColumnDesc(rgNewColumnDesc, m_cColumnDesc, TRUE);
	BaseTable.DropTable();
	RefTable.DropTable();
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(12)
//*-----------------------------------------------------------------------
// @mfunc On a primary key column
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCAddConstraint_FOREIGNKEY::Variation_12()
{ 
	TBEGIN
	CTable					BaseTable(m_pThisTestModule->m_pIUnknown2, (LPWSTR)gwszModuleName);
	CTable					RefTable(m_pThisTestModule->m_pIUnknown2, (LPWSTR)gwszModuleName);
	DBORDINAL				rgCol[] = {1};
	DBCOLUMNDESC			*rgNewColumnDesc	= NULL;
	DBID					*pTableID			= NULL;
	CForeignKeyCons			consFK;
	CPrimaryKeyCons			cons;
	CCol					col, col2;
	CConsDescArray			consArray;

	TESTC_(CreateTableWithNoNullableColumns(&BaseTable, 0), S_OK);
	BaseTable.BuildColumnDescs(&rgNewColumnDesc);

	TESTC_(RefTable.CreateTable(0, 0), S_OK);
	RefTable.AddInfoFromColumnsSchemaRowset(m_pITDWC, RefTable.GetTableName());
	
	// make the referenced columns unique
	TESTC_(AddUniqueConstraint(&RefTable, rgCol[0], (DBDEFERRABILITY)0), S_OK);

	// make the base column unique
	TESTC_(AddPrimaryKeyConstraint(&BaseTable, rgCol[0], (DBDEFERRABILITY)0), S_OK);

	// add FK constraint
	CHECK(AddForeignKeyConstraint(&BaseTable, NUMELEM(rgCol), rgCol, 
		&RefTable, NUMELEM(rgCol), rgCol, m_SupportedMatchType), S_OK);

	// try to create a table with a unique and a FK cons
	TESTC_(RefTable.GetColInfo(rgCol[0], col), S_OK);
	TESTC_(BaseTable.GetColInfo(rgCol[0], col2), S_OK);
	cons.AddColumn(col2.GetColID());
	consArray.AddConsDesc(cons);

	consFK.SetReferencedTableID(&RefTable.GetTableID());
	consFK.AddForeignKeyColumn(col2.GetColID());
	consFK.AddColumn(col.GetColID());
	consArray.AddConsDesc(consFK);

	TESTC_(cons.MakeConstraintName(), S_OK);
	if (CHECK(CreateAndCheckTableWithConstraints(m_pITDWC, NULL, NULL,
			m_cColumnDesc, rgNewColumnDesc, consArray, consArray, IID_IRowset, 0, NULL, 
			&pTableID, NULL), S_OK))
	{
		CHECK(DropTableAndCheck(pTableID, m_pITDWC), S_OK);
		ReleaseDBID(pTableID, TRUE);
	}

CLEANUP:
	ReleaseColumnDesc(rgNewColumnDesc, m_cColumnDesc, TRUE);
	BaseTable.DropTable();
	RefTable.DropTable();
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(13)
//*-----------------------------------------------------------------------
// @mfunc On a column that is part of the index
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCAddConstraint_FOREIGNKEY::Variation_13()
{ 
	TBEGIN
	CTable					BaseTable(m_pThisTestModule->m_pIUnknown2, (LPWSTR)gwszModuleName);
	CTable					RefTable(m_pThisTestModule->m_pIUnknown2, (LPWSTR)gwszModuleName);
	DBORDINAL				rgCol[] = {1};

	TESTC_(BaseTable.CreateTable(0, 1), S_OK);
	BaseTable.AddInfoFromColumnsSchemaRowset(m_pITDWC, BaseTable.GetTableName());
	TESTC_(RefTable.CreateTable(0, 1), S_OK);
	RefTable.AddInfoFromColumnsSchemaRowset(m_pITDWC, RefTable.GetTableName());
	
	// make the referenced columns unique
	TESTC_(AddUniqueConstraint(&RefTable, 1, (DBDEFERRABILITY)0), S_OK);

	TESTC_(AddForeignKeyConstraint(&BaseTable, NUMELEM(rgCol), rgCol, 
		&RefTable, NUMELEM(rgCol), rgCol, m_SupportedMatchType), S_OK);

CLEANUP:
	BaseTable.DropTable();
	RefTable.DropTable();
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(14)
//*-----------------------------------------------------------------------
// @mfunc On a table that is in another catalog
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCAddConstraint_FOREIGNKEY::Variation_14()
{ 
	TBEGIN
	CTable				BaseTable(m_pThisTestModule->m_pIUnknown2, (LPWSTR)gwszModuleName);
	CTable				ReferencedTable(m_pThisTestModule->m_pIUnknown2, (LPWSTR)gwszModuleName);
	DBORDINAL			rgBaseCol[] = {1};
	DBORDINAL			rgReferencedCol[] = {1};
	CCatalogs			Catalogs(m_pIOpenRowset);
	WCHAR				*pwszCurrentCatalog = NULL;
	WCHAR				*pwszCatalogName	= NULL;
	WCHAR				*pwszSchemaName		= NULL;
	WCHAR				*pwszQualTableName	= NULL;

	TESTC_PROVIDER(SettableProperty(DBPROP_CURRENTCATALOG, DBPROPSET_DATASOURCE, m_pIDBInitialize));
	TESTC_PROVIDER(1 < Catalogs.cCatalogs());

	// store the name of the current catalog
	TESTC(Catalogs.GetCurrentCatalog(&pwszCurrentCatalog));

	// change the current catalog
	TESTC_(Catalogs.ChangeCurrentCatalog(), S_OK);

	// create the referenced table in this catalog
	TESTC_PROVIDER(S_OK == ReferencedTable.CreateTable(0, 0));
	ReferencedTable.AddInfoFromColumnsSchemaRowset(m_pITDWC, ReferencedTable.GetTableName());
	// make the referenced columns unique
	TESTC_(AddUniqueConstraint(&ReferencedTable, rgReferencedCol[0], (DBDEFERRABILITY)0), S_OK);
	TESTC(GetCatalogSchemaNames(ReferencedTable.GetTableName(), &pwszCatalogName, &pwszSchemaName));

	//Construct a fully Qualified TableName...
	TESTC_(BaseTable.GetQualifiedName(pwszCatalogName, pwszSchemaName, ReferencedTable.GetTableName(), &pwszQualTableName),S_OK);
	ReferencedTable.SetTableName(pwszQualTableName);

	// switch back the current catalog
	TESTC_(Catalogs.SetCurrentCatalog(pwszCurrentCatalog), S_OK);

	// create the base table
	BaseTable.SetTableName(NULL);
	TESTC_(BaseTable.CreateTable(0, 0), S_OK);
	BaseTable.AddInfoFromColumnsSchemaRowset(m_pITDWC, BaseTable.GetTableName());
	
	// create the 
	CHECK(AddForeignKeyConstraint(&BaseTable, NUMELEM(rgBaseCol), rgBaseCol, 
		&ReferencedTable, NUMELEM(rgReferencedCol), rgReferencedCol, 
		m_SupportedMatchType), S_OK);

CLEANUP:
	if (pwszCurrentCatalog)
		// restore the name of the current catalog
		COMPARE(Catalogs.SetCurrentCatalog(pwszCurrentCatalog), S_OK);

	SAFE_FREE(pwszCurrentCatalog);
	SAFE_FREE(pwszCatalogName);
	SAFE_FREE(pwszSchemaName);
	SAFE_FREE(pwszQualTableName);
	BaseTable.DropTable();
	ReferencedTable.DropTable();
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(15)
//*-----------------------------------------------------------------------
// @mfunc Use different combination for update/delete rules, as well as match type
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCAddConstraint_FOREIGNKEY::Variation_15()
{ 
	TBEGIN
	CTable					BaseTable(m_pThisTestModule->m_pIUnknown2, (LPWSTR)gwszModuleName);
	CTable					RefTable(m_pThisTestModule->m_pIUnknown2, (LPWSTR)gwszModuleName);
	DBORDINAL				rgCol[] = {1};
	
	DBUPDELRULE				rgUPDLValues[] = {DBUPDELRULE_NOACTION, DBUPDELRULE_CASCADE,
								DBUPDELRULE_SETNULL, DBUPDELRULE_SETDEFAULT};
	WCHAR					*rgUPDLValuesText[] = {L"DBUPDELRULE_NOACTION", L"DBUPDELRULE_CASCADE",
								L"DBUPDELRULE_SETNULL", L"DBUPDELRULE_SETDEFAULT"};
	DBORDINAL				indexDelete;
	DBORDINAL				indexUpdate;
	
	DBMATCHTYPE				rgMatchType[] = {DBMATCHTYPE_NONE, DBMATCHTYPE_FULL, DBMATCHTYPE_PARTIAL};
	WCHAR					*rgMatchTypeText[] = {L"DBMATCHTYPE_NONE", L"DBMATCHTYPE_FULL", L"DBMATCHTYPE_PARTIAL"};
	DBORDINAL				indexMatchType;

	DBORDINAL				cSuccess = 0;
	HRESULT					hr;

	TESTC_(BaseTable.CreateTable(0, 1), S_OK);
	BaseTable.AddInfoFromColumnsSchemaRowset(m_pITDWC, BaseTable.GetTableName());
	TESTC_(RefTable.CreateTable(0, 0), S_OK);
	RefTable.AddInfoFromColumnsSchemaRowset(m_pITDWC, RefTable.GetTableName());
	
	// make the referenced columns unique
	TESTC_(AddUniqueConstraint(&RefTable, 1, (DBDEFERRABILITY)0), S_OK);

	for (indexDelete = 0; indexDelete < NUMELEM(rgUPDLValues); indexDelete++)
	{
		// all delete rules
		odtLog << "\t" << rgUPDLValuesText[indexDelete] << "\n";
		for (indexUpdate = 0; indexUpdate < NUMELEM(rgUPDLValues); indexUpdate++)
		{
			// all update rules
			odtLog << "\t\t" << rgUPDLValuesText[indexUpdate] << "\n";
			for (indexMatchType = 0; indexMatchType < NUMELEM(rgMatchType); indexMatchType++)
			{
				CForeignKeyCons	cons;

				// all match type rules
				odtLog << "\t\t\t" << rgMatchTypeText[indexMatchType];
				
				cons.SetConstraint(&BaseTable, NUMELEM(rgCol), rgCol, 
					&RefTable, NUMELEM(rgCol), rgCol, 
					rgMatchType[indexMatchType], 
					rgUPDLValues[indexUpdate], 
					rgUPDLValues[indexDelete], 
					(DBDEFERRABILITY)0);

				hr = AddConstraintAndCheck(m_pITDWC, &BaseTable.GetTableID(), cons);

				if (S_OK == hr)
				{
					odtLog << "\n";
					cSuccess++;
					CHECK(DropConstraintAndCheck(m_pITDWC, &BaseTable.GetTableID(), 
						cons.GetConstraintID()), S_OK);
				}
				else if (DB_E_BADUPDATEDELETERULE != hr && DB_E_BADMATCHTYPE!= hr)
				{
					CHECK(hr, S_OK);
				}
				else
					odtLog << "\tunsupported " << ((DB_E_BADUPDATEDELETERULE == hr) ? "rule" : "match type") << "\n";
			}
		}
	}

	TESTC(0 < cSuccess);

CLEANUP:
	BaseTable.DropTable();
	RefTable.DropTable();
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(16)
//*-----------------------------------------------------------------------
// @mfunc Referenced table name and base table names have maximum length
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCAddConstraint_FOREIGNKEY::Variation_16()
{ 
	TBEGIN
	CTable					BaseTable(m_pThisTestModule->m_pIUnknown2, (LPWSTR)gwszModuleName);
	CTable					RefTable(m_pThisTestModule->m_pIUnknown2, (LPWSTR)gwszModuleName);
	DBORDINAL				rgCol[] = {1};
	WCHAR					*pwszTableName = NULL;

	BaseTable.MakeTableName(NULL);
	pwszTableName = BuildValidName(m_cMaxTableName, BaseTable.GetTableName());

	TESTC_(BaseTable.CreateTable(0, 0, pwszTableName), S_OK);
	BaseTable.AddInfoFromColumnsSchemaRowset(m_pITDWC, BaseTable.GetTableName());
	TESTC_(RefTable.CreateTable(0, 0), S_OK);
	RefTable.AddInfoFromColumnsSchemaRowset(m_pITDWC, RefTable.GetTableName());
	
	// make the referenced columns unique
	TESTC_(AddUniqueConstraint(&RefTable, 1, (DBDEFERRABILITY)0), S_OK);

	TESTC_(AddForeignKeyConstraint(&BaseTable, NUMELEM(rgCol), rgCol, 
		&RefTable, NUMELEM(rgCol), rgCol, m_SupportedMatchType), S_OK);

CLEANUP:
	SAFE_FREE(pwszTableName);
	BaseTable.DropTable();
	RefTable.DropTable();
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(17)
//*-----------------------------------------------------------------------
// @mfunc Columns in the foreign key (base table and reference table) have different names
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCAddConstraint_FOREIGNKEY::Variation_17()
{ 
	TBEGIN
	CTable				BaseTable(m_pThisTestModule->m_pIUnknown2, (LPWSTR)gwszModuleName);
	CTable				RefTable(m_pThisTestModule->m_pIUnknown2, (LPWSTR)gwszModuleName);
	DBCOLUMNDESC		*rgNewColumnDesc = NULL;
	DBORDINAL			rgCol[] = {1};

	// the name of the column should be different
	DuplicateColumnDesc(m_rgColumnDesc, m_cColumnDesc, &rgNewColumnDesc);
	ReleaseDBID(&rgNewColumnDesc[0].dbcid, FALSE);
	rgNewColumnDesc[0].dbcid.eKind			= DBKIND_NAME;
	rgNewColumnDesc[0].dbcid.uName.pwszName	= wcsDuplicate(L"AnotherColumn");
	BaseTable.SetColumnDesc(rgNewColumnDesc, m_cColumnDesc);
	BaseTable.SetBuildColumnDesc(FALSE);

	TESTC_(BaseTable.CreateTable(0, 0), S_OK);
	BaseTable.AddInfoFromColumnsSchemaRowset(m_pITDWC, BaseTable.GetTableName());
	TESTC_(RefTable.CreateTable(0, 0), S_OK);
	RefTable.AddInfoFromColumnsSchemaRowset(m_pITDWC, RefTable.GetTableName());
	
	// make the referenced columns unique
	TESTC_(AddUniqueConstraint(&RefTable, 1, (DBDEFERRABILITY)0), S_OK);

	TESTC_(AddForeignKeyConstraint(&BaseTable, NUMELEM(rgCol), rgCol, 
		&RefTable, NUMELEM(rgCol), rgCol, m_SupportedMatchType), S_OK);

CLEANUP:
	BaseTable.DropTable();
	RefTable.DropTable();
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(18)
//*-----------------------------------------------------------------------
// @mfunc Different size in column lists (base table and referenced)
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCAddConstraint_FOREIGNKEY::Variation_18()
{ 
	TBEGIN
	CTable				BaseTable(m_pThisTestModule->m_pIUnknown2, (LPWSTR)gwszModuleName);
	CTable				RefTable(m_pThisTestModule->m_pIUnknown2, (LPWSTR)gwszModuleName);
	DBORDINAL			rgCol[] = {1};
	DBORDINAL			rgCol2[] = {1, 2};

	TESTC_(BaseTable.CreateTable(0, 0), S_OK);
	BaseTable.AddInfoFromColumnsSchemaRowset(m_pITDWC, BaseTable.GetTableName());
	TESTC_(RefTable.CreateTable(0, 0), S_OK);
	RefTable.AddInfoFromColumnsSchemaRowset(m_pITDWC, RefTable.GetTableName());
	
	// make the referenced columns unique
	TESTC_(AddUniqueConstraint(&RefTable, 1, (DBDEFERRABILITY)0), S_OK);

	TESTC_(AddForeignKeyConstraint(&BaseTable, NUMELEM(rgCol), rgCol, 
		&RefTable, NUMELEM(rgCol2), rgCol2, m_SupportedMatchType), E_INVALIDARG);
	TESTC_(AddForeignKeyConstraint(&BaseTable, NUMELEM(rgCol), rgCol, 
		&RefTable, NUMELEM(rgCol2), rgCol2, m_SupportedMatchType), E_INVALIDARG);

CLEANUP:
	BaseTable.DropTable();
	RefTable.DropTable();
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(19)
//*-----------------------------------------------------------------------
// @mfunc Column types in base table and reference table are different
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCAddConstraint_FOREIGNKEY::Variation_19()
{ 
	TBEGIN
	CTable				BaseTable(m_pThisTestModule->m_pIUnknown2, (LPWSTR)gwszModuleName);
	CTable				ReferencedTable(m_pThisTestModule->m_pIUnknown2, (LPWSTR)gwszModuleName);
	DBORDINAL			rgBaseCol[] = {1};
	DBORDINAL			rgReferencedCol[] = {3};
	CCol				col;
	HRESULT				hr;
	CForeignKeyCons		cons(NULL, m_SupportedMatchType);

	TESTC_(BaseTable.CreateTable(0, 0), S_OK);
	BaseTable.AddInfoFromColumnsSchemaRowset(m_pITDWC, BaseTable.GetTableName());
	TESTC_(ReferencedTable.CreateTable(0, 0), S_OK);
	ReferencedTable.AddInfoFromColumnsSchemaRowset(m_pITDWC, ReferencedTable.GetTableName());
	
	// find 2 columns of different types (DBTYPE_I4 and DBTYPE_R4)
	TESTC_PROVIDER(S_OK == ReferencedTable.GetColInfo(col, DBTYPE_I4));
	rgReferencedCol[0] = col.GetColNum();
	TESTC_PROVIDER(S_OK == BaseTable.GetColInfo(col, DBTYPE_R4));
	rgBaseCol[0] = col.GetColNum();

	// make the referenced columns unique
	TESTC_(AddUniqueConstraint(&ReferencedTable, rgReferencedCol[0], (DBDEFERRABILITY)0), S_OK);

	CHECK(ReferencedTable.GetColInfo(rgReferencedCol[0], col), S_OK);
	cons.AddColumn(col.GetColID());
	CHECK(BaseTable.GetColInfo(rgBaseCol[0], col), S_OK);
	cons.AddForeignKeyColumn(col.GetColID());
	cons.SetReferencedTableID(&ReferencedTable.GetTableID());

	CHECK(hr = AddConstraintAndCheck(m_pITDWC, &BaseTable.GetTableID(), cons, TRUE), DB_E_BADCONSTRAINTFORM);

	if (S_OK == hr)
	{
		// challenge the constraint
		TESTC_(ReferencedTable.Insert(12), S_OK);
		TESTC_(BaseTable.Insert(12), S_OK);
	}

CLEANUP:
	BaseTable.DropTable();
	ReferencedTable.DropTable();
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(20)
//*-----------------------------------------------------------------------
// @mfunc Invalid value for the update rule
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCAddConstraint_FOREIGNKEY::Variation_20()
{ 
	TBEGIN
	CTable				BaseTable(m_pThisTestModule->m_pIUnknown2, (LPWSTR)gwszModuleName);
	CTable				ReferencedTable(m_pThisTestModule->m_pIUnknown2, (LPWSTR)gwszModuleName);
	DBORDINAL			rgBaseCol[] = {1};
	DBORDINAL			rgReferencedCol[] = {1};

	TESTC_(BaseTable.CreateTable(0, 0), S_OK);
	BaseTable.AddInfoFromColumnsSchemaRowset(m_pITDWC, BaseTable.GetTableName());
	TESTC_(ReferencedTable.CreateTable(0, 0), S_OK);
	ReferencedTable.AddInfoFromColumnsSchemaRowset(m_pITDWC, ReferencedTable.GetTableName());
	
	// make the referenced columns unique
	TESTC_(AddUniqueConstraint(&ReferencedTable, rgReferencedCol[0], (DBDEFERRABILITY)0), S_OK);

	CHECK(AddForeignKeyConstraint(&BaseTable, NUMELEM(rgBaseCol), rgBaseCol, 
		&ReferencedTable, NUMELEM(rgReferencedCol), rgReferencedCol, 
		m_SupportedMatchType, 0xFF), DB_E_BADUPDATEDELETERULE);

CLEANUP:
	BaseTable.DropTable();
	ReferencedTable.DropTable();
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(21)
//*-----------------------------------------------------------------------
// @mfunc Invalid value for the delete rule
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCAddConstraint_FOREIGNKEY::Variation_21()
{ 
	TBEGIN
	CTable				BaseTable(m_pThisTestModule->m_pIUnknown2, (LPWSTR)gwszModuleName);
	CTable				ReferencedTable(m_pThisTestModule->m_pIUnknown2, (LPWSTR)gwszModuleName);
	DBORDINAL			rgBaseCol[] = {1};
	DBORDINAL			rgReferencedCol[] = {1};

	TESTC_(BaseTable.CreateTable(0, 0), S_OK);
	BaseTable.AddInfoFromColumnsSchemaRowset(m_pITDWC, BaseTable.GetTableName());
	TESTC_(ReferencedTable.CreateTable(0, 0), S_OK);
	ReferencedTable.AddInfoFromColumnsSchemaRowset(m_pITDWC, ReferencedTable.GetTableName());
	
	// make the referenced columns unique
	TESTC_(AddUniqueConstraint(&ReferencedTable, rgReferencedCol[0], (DBDEFERRABILITY)0), S_OK);

	CHECK(AddForeignKeyConstraint(&BaseTable, NUMELEM(rgBaseCol), rgBaseCol, 
		&ReferencedTable, NUMELEM(rgReferencedCol), rgReferencedCol, 
		m_SupportedMatchType, DBUPDELRULE_NOACTION, 0xFF), DB_E_BADUPDATEDELETERULE);

CLEANUP:
	BaseTable.DropTable();
	ReferencedTable.DropTable();
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(22)
//*-----------------------------------------------------------------------
// @mfunc Invalid value for the MatchType
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCAddConstraint_FOREIGNKEY::Variation_22()
{ 
	TBEGIN
	CTable				BaseTable(m_pThisTestModule->m_pIUnknown2, (LPWSTR)gwszModuleName);
	CTable				ReferencedTable(m_pThisTestModule->m_pIUnknown2, (LPWSTR)gwszModuleName);
	DBORDINAL			rgBaseCol[] = {1};
	DBORDINAL			rgReferencedCol[] = {1};

	TESTC_(BaseTable.CreateTable(0, 0), S_OK);
	BaseTable.AddInfoFromColumnsSchemaRowset(m_pITDWC, BaseTable.GetTableName());
	TESTC_(ReferencedTable.CreateTable(0, 0), S_OK);
	ReferencedTable.AddInfoFromColumnsSchemaRowset(m_pITDWC, ReferencedTable.GetTableName());
	
	// make the referenced columns unique
	TESTC_(AddUniqueConstraint(&ReferencedTable, rgReferencedCol[0], (DBDEFERRABILITY)0), S_OK);

	CHECK(AddForeignKeyConstraint(&BaseTable, NUMELEM(rgBaseCol), rgBaseCol, 
		&ReferencedTable, NUMELEM(rgReferencedCol), rgReferencedCol, 
		0xFF), DB_E_BADMATCHTYPE);

CLEANUP:
	BaseTable.DropTable();
	ReferencedTable.DropTable();
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(23)
//*-----------------------------------------------------------------------
// @mfunc Inexistent column names in the referenced table
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCAddConstraint_FOREIGNKEY::Variation_23()
{ 
	TBEGIN
	CTable				BaseTable(m_pThisTestModule->m_pIUnknown2, (LPWSTR)gwszModuleName);
	CTable				ReferencedTable(m_pThisTestModule->m_pIUnknown2, (LPWSTR)gwszModuleName);
	DBORDINAL			rgBaseCol[] = {1};
	DBORDINAL			rgReferencedCol[] = {1};
	CForeignKeyCons		cons;

	TESTC_(BaseTable.CreateTable(0, 0), S_OK);
	BaseTable.AddInfoFromColumnsSchemaRowset(m_pITDWC, BaseTable.GetTableName());
	TESTC_(ReferencedTable.CreateTable(0, 0), S_OK);
	ReferencedTable.AddInfoFromColumnsSchemaRowset(m_pITDWC, ReferencedTable.GetTableName());
	
	// make the referenced columns unique
	TESTC_(AddUniqueConstraint(&ReferencedTable, rgReferencedCol[0], (DBDEFERRABILITY)0), S_OK);

	TESTC_(cons.SetConstraint(&BaseTable, NUMELEM(rgBaseCol), rgBaseCol, 
		&ReferencedTable, NUMELEM(rgReferencedCol), rgReferencedCol, m_SupportedMatchType), S_OK);

	// release the referenced column and set inexistent name
	SAFE_FREE(((DBCONSTRAINTDESC*)cons)->rgColumnList[0].uName.pwszName);
	((DBCONSTRAINTDESC*)cons)->rgColumnList[0].uName.pwszName = wcsDuplicate(L"NuExista");

	TESTC_(AddConstraintAndCheck(m_pITDWC, &BaseTable.GetTableID(), cons), DB_E_NOCOLUMN);

CLEANUP:
	BaseTable.DropTable();
	ReferencedTable.DropTable();
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(24)
//*-----------------------------------------------------------------------
// @mfunc Inexistent column name in the base table
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCAddConstraint_FOREIGNKEY::Variation_24()
{ 
	TBEGIN
	CTable				BaseTable(m_pThisTestModule->m_pIUnknown2, (LPWSTR)gwszModuleName);
	CTable				ReferencedTable(m_pThisTestModule->m_pIUnknown2, (LPWSTR)gwszModuleName);
	DBORDINAL			rgBaseCol[] = {1};
	DBORDINAL			rgReferencedCol[] = {1};
	CForeignKeyCons		cons;

	TESTC_(BaseTable.CreateTable(0, 0), S_OK);
	BaseTable.AddInfoFromColumnsSchemaRowset(m_pITDWC, BaseTable.GetTableName());
	TESTC_(ReferencedTable.CreateTable(0, 0), S_OK);
	ReferencedTable.AddInfoFromColumnsSchemaRowset(m_pITDWC, ReferencedTable.GetTableName());
	
	// make the referenced columns unique
	TESTC_(AddUniqueConstraint(&ReferencedTable, rgReferencedCol[0], (DBDEFERRABILITY)0), S_OK);

	TESTC_(cons.SetConstraint(&BaseTable, NUMELEM(rgBaseCol), rgBaseCol, 
		&ReferencedTable, NUMELEM(rgReferencedCol), rgReferencedCol, m_SupportedMatchType), S_OK);

	// release the referenced column and set inexistent name
	SAFE_FREE(((DBCONSTRAINTDESC*)cons)->rgForeignKeyColumnList[0].uName.pwszName);
	((DBCONSTRAINTDESC*)cons)->rgForeignKeyColumnList[0].uName.pwszName = wcsDuplicate(L"NuExista");

	TESTC_(AddConstraintAndCheck(m_pITDWC, &BaseTable.GetTableID(), cons), DB_E_NOCOLUMN);

CLEANUP:
	BaseTable.DropTable();
	ReferencedTable.DropTable();
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(25)
//*-----------------------------------------------------------------------
// @mfunc Inexistent base table
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCAddConstraint_FOREIGNKEY::Variation_25()
{ 
	TBEGIN
	CTable				BaseTable(m_pThisTestModule->m_pIUnknown2, (LPWSTR)gwszModuleName);
	CTable				ReferencedTable(m_pThisTestModule->m_pIUnknown2, (LPWSTR)gwszModuleName);
	DBORDINAL			rgBaseCol[] = {1};
	DBORDINAL			rgReferencedCol[] = {1};
	CForeignKeyCons		cons;

	TESTC_(ReferencedTable.CreateTable(0, 0), S_OK);
	ReferencedTable.AddInfoFromColumnsSchemaRowset(m_pITDWC, ReferencedTable.GetTableName());
	
	// make the referenced columns unique
	TESTC_(AddUniqueConstraint(&ReferencedTable, rgReferencedCol[0], (DBDEFERRABILITY)0), S_OK);

	// since base table name has to be inexistent, use reference table name instead
	TESTC_(cons.SetConstraint(&ReferencedTable, NUMELEM(rgBaseCol), rgBaseCol, 
		&ReferencedTable, NUMELEM(rgReferencedCol), rgReferencedCol, m_SupportedMatchType), S_OK);

	TESTC_(BaseTable.MakeTableName(NULL), S_OK);
	TESTC_(AddConstraintAndCheck(m_pITDWC, &BaseTable.GetTableID(), cons), DB_E_NOTABLE);

CLEANUP:
	BaseTable.DropTable();
	ReferencedTable.DropTable();
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(26)
//*-----------------------------------------------------------------------
// @mfunc Inexistent reference table
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCAddConstraint_FOREIGNKEY::Variation_26()
{ 
	TBEGIN
	CTable				BaseTable(m_pThisTestModule->m_pIUnknown2, (LPWSTR)gwszModuleName);
	CTable				ReferencedTable(m_pThisTestModule->m_pIUnknown2, (LPWSTR)gwszModuleName);
	DBORDINAL			rgBaseCol[] = {1};
	DBORDINAL			rgReferencedCol[] = {1};
	CForeignKeyCons		cons;

	TESTC_(BaseTable.CreateTable(0, 0), S_OK);
	BaseTable.AddInfoFromColumnsSchemaRowset(m_pITDWC, BaseTable.GetTableName());
	
	// since base table name has to be inexistent, use reference table name instead
	TESTC_(cons.SetConstraint(&BaseTable, NUMELEM(rgBaseCol), rgBaseCol, 
		&BaseTable, NUMELEM(rgReferencedCol), rgReferencedCol, m_SupportedMatchType), S_OK);

	// fill-in an inexistent table name
	TESTC_(ReferencedTable.MakeTableName(NULL), S_OK);
	ReleaseDBID(((DBCONSTRAINTDESC*)cons)->pReferencedTableID, FALSE);
	TESTC_(DuplicateDBID(ReferencedTable.GetTableID(), ((DBCONSTRAINTDESC*)cons)->pReferencedTableID), S_OK);

	TESTC_(AddConstraintAndCheck(m_pITDWC, &BaseTable.GetTableID(), cons), DB_E_NOTABLE);

CLEANUP:
	BaseTable.DropTable();
	ReferencedTable.DropTable();
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(27)
//*-----------------------------------------------------------------------
// @mfunc NULL pConstraintID
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCAddConstraint_FOREIGNKEY::Variation_27()
{ 
	TBEGIN
	CTable				BaseTable(m_pThisTestModule->m_pIUnknown2, (LPWSTR)gwszModuleName);
	CTable				ReferencedTable(m_pThisTestModule->m_pIUnknown2, (LPWSTR)gwszModuleName);
	DBORDINAL			rgBaseCol[] = {1};
	DBORDINAL			rgReferencedCol[] = {1};
	CForeignKeyCons		cons;

	TESTC_(BaseTable.CreateTable(0, 0), S_OK);
	BaseTable.AddInfoFromColumnsSchemaRowset(m_pITDWC, BaseTable.GetTableName());
	TESTC_(ReferencedTable.CreateTable(0, 0), S_OK);
	ReferencedTable.AddInfoFromColumnsSchemaRowset(m_pITDWC, ReferencedTable.GetTableName());
	
	// make the referenced columns unique
	TESTC_(AddUniqueConstraint(&ReferencedTable, rgReferencedCol[0], (DBDEFERRABILITY)0), S_OK);

	TESTC_(cons.SetConstraint(&BaseTable, NUMELEM(rgBaseCol), rgBaseCol, 
		&ReferencedTable, NUMELEM(rgReferencedCol), rgReferencedCol, m_SupportedMatchType), S_OK);

	// release pConstraintID
	ReleaseDBID(((DBCONSTRAINTDESC*)cons)->pConstraintID, TRUE);
	((DBCONSTRAINTDESC*)cons)->pConstraintID = NULL;

	TESTC_(AddConstraintAndCheck(m_pITDWC, &BaseTable.GetTableID(), cons), S_OK);

CLEANUP:
	BaseTable.DropTable();
	ReferencedTable.DropTable();
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(28)
//*-----------------------------------------------------------------------
// @mfunc Referenced col list is not a unique / pk constraint => failure
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCAddConstraint_FOREIGNKEY::Variation_28()
{ 
	TBEGIN
	CTable					ReferencedTable(m_pThisTestModule->m_pIUnknown2, (LPWSTR)gwszModuleName);
	CTable					BaseTable(m_pThisTestModule->m_pIUnknown2, (LPWSTR)gwszModuleName);
	CCol					col, col2;
	DBORDINAL				indexCol = 1;
	CForeignKeyCons			cons(NULL, m_SupportedMatchType);

	TESTC_(ReferencedTable.CreateTable(0, 0), S_OK);
	ReferencedTable.AddInfoFromColumnsSchemaRowset(m_pITDWC, ReferencedTable.GetTableName());
	TESTC_(BaseTable.CreateTable(0, 0), S_OK);
	BaseTable.AddInfoFromColumnsSchemaRowset(m_pITDWC, BaseTable.GetTableName());
	
	// select columns from tables
	TESTC(BaseTable.CountColumnsOnTable() == ReferencedTable.CountColumnsOnTable())
	TESTC_(BaseTable.GetColInfo(indexCol, col), S_OK);
	TESTC_(ReferencedTable.GetColInfo(indexCol, col2), S_OK);

	// build the foreign key constraint, use corresponding columns in tables
	cons.AddColumn(col2.GetColID());
	cons.AddForeignKeyColumn(col.GetColID());
	cons.SetReferencedTableID(&ReferencedTable.GetTableID());

	// add the foreign key constraint
	TESTC_(AddConstraintAndCheck(m_pITDWC, &BaseTable.GetTableID(), cons), E_FAIL);

CLEANUP:
	BaseTable.DropTable();
	ReferencedTable.DropTable();
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(29)
//*-----------------------------------------------------------------------
// @mfunc Create a foreign key and then insert a NULL value for one of the fk columns
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCAddConstraint_FOREIGNKEY::Variation_29()
{ 
	TBEGIN
	CTable					BaseTable(m_pThisTestModule->m_pIUnknown2, (LPWSTR)gwszModuleName);
	CTable					ReferencedTable(m_pThisTestModule->m_pIUnknown2, (LPWSTR)gwszModuleName);
	DBORDINAL				rgCols[] = {1, 2, 3};
		
	IRowsetChange			*pIRowsetChange = NULL;

	DBMATCHTYPE				rgMatchType[] = {DBMATCHTYPE_NONE, DBMATCHTYPE_FULL, DBMATCHTYPE_PARTIAL};
	WCHAR					*rgMatchTypeText[] = {L"DBMATCHTYPE_NONE", L"DBMATCHTYPE_FULL", L"DBMATCHTYPE_PARTIAL"};
	DBORDINAL				indexMatchType;

	DBORDINAL				cSuccess = 0;
	HRESULT					hr;

	const DBORDINAL			cProp = 1;
	DBPROP					rgProp[cProp];

	const DBORDINAL			cPropSets = 1;
	DBPROPSET				rgPropSets[cPropSets];

	rgPropSets[0].guidPropertySet	= DBPROPSET_ROWSET;
	rgPropSets[0].cProperties		= 1;
	rgPropSets[0].rgProperties		= rgProp;
	
	memset(rgProp, 0, sizeof(DBPROP));
	rgProp[0].dwPropertyID			= DBPROP_UPDATABILITY;
	rgProp[0].vValue.vt				= VT_I4;
	V_I4(&rgProp[0].vValue)			= DBPROPVAL_UP_INSERT;

	CList<WCHAR *,WCHAR *>	NativeTypesList;
	CList<DBTYPE,DBTYPE>	ProviderTypesList;
	DBCOLUMNDESC			*rgColumnDesc = NULL;

	BaseTable.CreateTypeColInfo(NativeTypesList, ProviderTypesList);
	TESTC_PROVIDER(2 < m_cColumnDesc);
	// create a new table with a NOT NULLABLE column
	DuplicateColumnDesc(m_rgColumnDesc, m_cColumnDesc, &rgColumnDesc);
	SetProperty(&rgColumnDesc[0].rgPropertySets, &rgColumnDesc[0].cPropertySets,
			DBPROP_COL_NULLABLE, 
			VT_BOOL, (LPVOID)VARIANT_TRUE, 
			DBPROPOPTIONS_REQUIRED);
	SetProperty(&rgColumnDesc[1].rgPropertySets, &rgColumnDesc[1].cPropertySets,
			DBPROP_COL_NULLABLE, 
			VT_BOOL, (LPVOID)VARIANT_TRUE, 
			DBPROPOPTIONS_REQUIRED);
	SetProperty(&rgColumnDesc[2].rgPropertySets, &rgColumnDesc[2].cPropertySets,
			DBPROP_COL_NULLABLE, 
			VT_BOOL, (LPVOID)VARIANT_TRUE, 
			DBPROPOPTIONS_REQUIRED);
	BaseTable.SetColumnDesc(rgColumnDesc, m_cColumnDesc);
	BaseTable.SetBuildColumnDesc(FALSE);
	
	TESTC_PROVIDER(S_OK == BaseTable.CreateTable(0, 0));
	BaseTable.AddInfoFromColumnsSchemaRowset(m_pITDWC, BaseTable.GetTableName());
	TESTC_(CreateTableWithNoNullableColumns(&ReferencedTable, 5, 0), S_OK);
	
	// make the referenced columns unique
	TESTC_(AddUniqueConstraint(&ReferencedTable, NUMELEM(rgCols), rgCols, (DBDEFERRABILITY)0), S_OK);

	for (indexMatchType = 0; indexMatchType < NUMELEM(rgMatchType); indexMatchType++)
	{
		CForeignKeyCons	cons;

		// all match type rules
		odtLog << "\t\t\t" << rgMatchTypeText[indexMatchType];
		
		cons.SetConstraint(&BaseTable, NUMELEM(rgCols), rgCols, 
			&ReferencedTable, NUMELEM(rgCols), rgCols, 
			rgMatchType[indexMatchType], 
			DBUPDELRULE_NOACTION, 
			DBUPDELRULE_NOACTION, 
			(DBDEFERRABILITY)0);

		hr = AddConstraintAndCheck(m_pITDWC, &BaseTable.GetTableID(), cons);

		if (S_OK == hr)
		{
			odtLog << "\n";
			cSuccess++;
			{
				// open a rowset on the base table
				TESTC_(g_pIOpenRowset->OpenRowset(NULL, &BaseTable.GetTableID(), NULL,
					IID_IRowsetChange, cPropSets, rgPropSets, (IUnknown**)&pIRowsetChange), S_OK);

				// try to insert a NULL in the second column
				// this should succeed if the match type is partial and the rest
				// of the key matches a rows in the referenced table 
				CHECK(Insert(3, pIRowsetChange, 1, rgCols + 1, &BaseTable), 
					(DBMATCHTYPE_FULL != rgMatchType[indexMatchType])? S_OK: DB_E_INTEGRITYVIOLATION);
				CHECK(Insert(3, pIRowsetChange, 3, rgCols, &BaseTable), S_OK);
					//(DBMATCHTYPE_FULL == rgMatchType[indexMatchType])? S_OK: DB_E_INTEGRITYVIOLATION);
				CHECK(Insert(32, pIRowsetChange, 1, rgCols + 1, &BaseTable), 
					(DBMATCHTYPE_NONE == rgMatchType[indexMatchType])? S_OK: DB_E_INTEGRITYVIOLATION);
				SAFE_RELEASE(pIRowsetChange);
			}

			CHECK(DropConstraintAndCheck(m_pITDWC, &BaseTable.GetTableID(), 
				cons.GetConstraintID()), S_OK);
		}
		else if (DB_E_BADMATCHTYPE!= hr)
		{
			CHECK(hr, S_OK);
		}
		else
			odtLog << "\tunsupported " << ((DB_E_BADUPDATEDELETERULE == hr) ? "rule" : "match type") << "\n";
	}

	TESTC(0 < cSuccess);

CLEANUP:
	SAFE_RELEASE(pIRowsetChange);
	BaseTable.DropTable();
	ReferencedTable.DropTable();
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(30)
//*-----------------------------------------------------------------------
// @mfunc The referenced table and the base table are the same
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCAddConstraint_FOREIGNKEY::Variation_30()
{ 
	TBEGIN
	CTable					Table(m_pThisTestModule->m_pIUnknown2, (LPWSTR)gwszModuleName);
	CCol					col, col2;
	DBORDINAL				indexCol = 1;
	HRESULT					hr;
	CForeignKeyCons			cons(NULL, m_SupportedMatchType);
	DBCOLUMNDESC			*rgColumnDesc;
	
	DuplicateColumnDesc(m_rgColumnDesc, 1, &rgColumnDesc);
	ReleaseDBID(&rgColumnDesc[0].dbcid, FALSE);
	rgColumnDesc[0].dbcid.eKind = DBKIND_NAME;
	rgColumnDesc[0].dbcid.uName.pwszName = wcsDuplicate(L"NewColumn");

	ReleaseAllColumnPropSets(rgColumnDesc, 1);

	TESTC_(Table.CreateTable(0, 0), S_OK);
	Table.AddInfoFromColumnsSchemaRowset(m_pITDWC, Table.GetTableName());
	
	TESTC_(AddUniqueConstraint(&Table, indexCol), S_OK);

	TESTC_(AddColumnAndCheck(&Table.GetTableID(), rgColumnDesc, NULL, m_pITDWC), S_OK);

	// select columns from tables
	TESTC_(Table.GetColInfo(indexCol, col), S_OK);

	// build the foreign key constraint, use corresponding columns in tables
	cons.AddColumn(col.GetColID());
	cons.AddForeignKeyColumn(&rgColumnDesc[0].dbcid);
	cons.SetReferencedTableID(&Table.GetTableID());

	// add the foreign key constraint
	hr = AddConstraintAndCheck(m_pITDWC, &Table.GetTableID(), cons);

	TEST2C_(hr, S_OK, DB_E_BADMATCHTYPE);

CLEANUP:
	ReleaseColumnDesc(rgColumnDesc, 1);
	Table.DropTable();
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(31)
//*-----------------------------------------------------------------------
// @mfunc The base and referenced tables are temporary tables
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCAddConstraint_FOREIGNKEY::Variation_31()
{ 
	TBEGIN
	CCol					col;
	DBORDINAL				indexCol = 1;
	CForeignKeyCons			cons(NULL, m_SupportedMatchType);
	CUniqueCons				UniqueCons;

	DBID					*pBaseTableID = NULL;
	DBID					*pReferencedTableID = NULL;
	DBPROPSET				rgPropSets[1];
	DBPROP					rgProp[1];
	DBCOLUMNDESC			*rgColumnDesc	= NULL;
	DBORDINAL				cColumnDesc		= 0;

	TESTC_PROVIDER(SettableProperty(DBPROP_TBL_TEMPTABLE, DBPROPSET_TABLE));
	DuplicateColumnDesc(m_rgColumnDesc, m_cColumnDesc, &rgColumnDesc);
	cColumnDesc = m_cColumnDesc;
	ReleaseAllColumnPropSets(rgColumnDesc, cColumnDesc);

	// temp table, TableID generated by provider
	FILL_PROP_SET(rgPropSets[0], NUMELEM(rgProp), rgProp, DBPROPSET_TABLE);
	FILL_PROP(rgProp[0], DBPROP_TBL_TEMPTABLE, VT_BOOL, V_BOOL, VARIANT_TRUE, DBPROPOPTIONS_REQUIRED);

	TESTC_(CreateAndCheckTable(m_pITDWC, NULL, NULL, cColumnDesc, rgColumnDesc, 
		IID_IRowset, NUMELEM(rgPropSets), rgPropSets, &pReferencedTableID, NULL), S_OK);
	
	UniqueCons.AddColumn(&rgColumnDesc[0].dbcid);
	TESTC_(AddConstraintAndCheck(m_pITDWC, pReferencedTableID, UniqueCons), S_OK);

	TESTC_(CreateAndCheckTable(m_pITDWC, NULL, NULL, cColumnDesc, rgColumnDesc, 
		IID_IRowset, NUMELEM(rgPropSets), rgPropSets, &pBaseTableID, NULL), S_OK);
	
	// select columns from tables
	// build the foreign key constraint, use corresponding columns in tables
	cons.AddColumn(&rgColumnDesc[0].dbcid);
	cons.AddForeignKeyColumn(&rgColumnDesc[0].dbcid);
	cons.SetReferencedTableID(pReferencedTableID);

	// add the foreign key constraint
	TESTC_(AddConstraintAndCheck(m_pITDWC, pBaseTableID, cons), S_OK);

CLEANUP:
	DropTableAndCheck(pBaseTableID);
	DropTableAndCheck(pReferencedTableID);
	ReleaseColumnDesc(rgColumnDesc, cColumnDesc);
	ReleaseDBID(pReferencedTableID, TRUE);
	ReleaseDBID(pBaseTableID, TRUE);
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(32)
//*-----------------------------------------------------------------------
// @mfunc Base table is a temporary table
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCAddConstraint_FOREIGNKEY::Variation_32()
{ 
	TBEGIN
	CTable					ReferencedTable(m_pThisTestModule->m_pIUnknown2, (LPWSTR)gwszModuleName);
	CCol					col;
	DBORDINAL				indexCol = 1;
	CForeignKeyCons			cons(NULL, m_SupportedMatchType);

	DBID					*pBaseTableID = NULL;
	DBPROPSET				rgPropSets[1];
	DBPROP					rgProp[1];
	DBCOLUMNDESC			*rgColumnDesc	= NULL;
	DBORDINAL				cColumnDesc		= 0;

	TESTC_PROVIDER(SettableProperty(DBPROP_TBL_TEMPTABLE, DBPROPSET_TABLE));
	DuplicateColumnDesc(m_rgColumnDesc, m_cColumnDesc, &rgColumnDesc);
	cColumnDesc = m_cColumnDesc;
	ReleaseAllColumnPropSets(rgColumnDesc, cColumnDesc);

	// temp table, TableID generated by provider
	FILL_PROP_SET(rgPropSets[0], NUMELEM(rgProp), rgProp, DBPROPSET_TABLE);
	FILL_PROP(rgProp[0], DBPROP_TBL_TEMPTABLE, VT_BOOL, V_BOOL, VARIANT_TRUE, DBPROPOPTIONS_REQUIRED);

	TESTC_(CreateAndCheckTable(m_pITDWC, NULL, NULL, cColumnDesc, rgColumnDesc, 
		IID_IRowset, NUMELEM(rgPropSets), rgPropSets, &pBaseTableID, NULL), S_OK);

	TESTC_(ReferencedTable.CreateTable(0, 0), S_OK);
	ReferencedTable.AddInfoFromColumnsSchemaRowset(m_pITDWC, ReferencedTable.GetTableName());
	
	TESTC_(AddUniqueConstraint(&ReferencedTable, indexCol), S_OK);
	
	// select columns from tables
	TESTC(ReferencedTable.CountColumnsOnTable() == cColumnDesc)
	TESTC_(ReferencedTable.GetColInfo(indexCol, col), S_OK);

	// build the foreign key constraint, use corresponding columns in tables
	cons.AddColumn(col.GetColID());
	cons.AddForeignKeyColumn(&rgColumnDesc[0].dbcid);
	cons.SetReferencedTableID(&ReferencedTable.GetTableID());

	// add the foreign key constraint
	TESTC_(AddConstraintAndCheck(m_pITDWC, pBaseTableID, cons), S_OK);

CLEANUP:
	DropTableAndCheck(pBaseTableID);
	ReleaseColumnDesc(rgColumnDesc, cColumnDesc);
	ReleaseDBID(pBaseTableID, TRUE);
	ReferencedTable.DropTable();
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(33)
//*-----------------------------------------------------------------------
// @mfunc Abort retaining
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCAddConstraint_FOREIGNKEY::Variation_33()
{ 
	CAddFKConsTxnAdapter	TxnAdapter(this);
	CTransactionLocal		TxnLocal;

	return TxnLocal.DoTransactionTest(m_pITDWC, &TxnAdapter,
		TRUE,		// DDL
		TRUE,		// Abort
		TRUE		// Retaining
		);
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(34)
//*-----------------------------------------------------------------------
// @mfunc Abort non retaining
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCAddConstraint_FOREIGNKEY::Variation_34()
{ 
	CAddFKConsTxnAdapter	TxnAdapter(this);
	CTransactionLocal		TxnLocal;

	return TxnLocal.DoTransactionTest(m_pITDWC, &TxnAdapter,
		TRUE,		// DDL
		TRUE,		// Abort
		FALSE		// Non Retaining
		);
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(35)
//*-----------------------------------------------------------------------
// @mfunc Commit retaining
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCAddConstraint_FOREIGNKEY::Variation_35()
{ 
	CAddFKConsTxnAdapter	TxnAdapter(this);
	CTransactionLocal		TxnLocal;

	return TxnLocal.DoTransactionTest(m_pITDWC, &TxnAdapter,
		TRUE,		// DDL
		FALSE,		// Commit
		TRUE		// Retaining
		);
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(36)
//*-----------------------------------------------------------------------
// @mfunc Commit non retaining
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCAddConstraint_FOREIGNKEY::Variation_36()
{ 
	CAddFKConsTxnAdapter	TxnAdapter(this);
	CTransactionLocal		TxnLocal;

	return TxnLocal.DoTransactionTest(m_pITDWC, &TxnAdapter,
		TRUE,		// DDL
		FALSE,		// Commit
		FALSE		// Non Retaining
		);
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(37)
//*-----------------------------------------------------------------------
// @mfunc The base table is already populated and the referenced one is empty => DB_E_SCHEMAVIOLATION
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCAddConstraint_FOREIGNKEY::Variation_37()
{ 
	TBEGIN
	CTable					BaseTable(m_pThisTestModule->m_pIUnknown2, (LPWSTR)gwszModuleName);
	CCol					col, col2;
	DBORDINAL				indexCol = 1;
	CForeignKeyCons			cons(NULL, m_SupportedMatchType);

	TESTC_(BaseTable.CreateTable(5, 0), S_OK);
	
	// select columns from tables
	BaseTable.AddInfoFromColumnsSchemaRowset(m_pITDWC, BaseTable.GetTableName());
	TESTC(BaseTable.CountColumnsOnTable() == m_pReferenceTable->CountColumnsOnTable())
	TESTC_(BaseTable.GetColInfo(indexCol, col), S_OK);
	TESTC_(m_pReferenceTable->GetColInfo(indexCol, col2), S_OK);

	// build the foreign key constraint, use corresponding columns in tables
	cons.AddColumn(col2.GetColID());
	cons.AddForeignKeyColumn(col.GetColID());
	cons.SetReferencedTableID(&m_pReferenceTable->GetTableID());

	// add the foreign key constraint
	TESTC_(AddConstraintAndCheck(m_pITDWC, &BaseTable.GetTableID(), cons), DB_E_SCHEMAVIOLATION);

CLEANUP:
	BaseTable.DropTable();
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END


int TCAddConstraint_FOREIGNKEY::Variation_38() {
	TBEGIN

	CLimitTable			Table;

	TESTC_(Table.CheckForeignKeyLimit(), S_OK);

CLEANUP:
	TRETURN
}



// {{ TCW_TERMINATE_METHOD
//*-----------------------------------------------------------------------
// @mfunc TestCase Termination Routine 
//
// @rdesc TEST_PASS or TEST_FAIL 
//
BOOL TCAddConstraint_FOREIGNKEY::Terminate()
{ 
	if (m_pReferenceTable)
		m_pReferenceTable->DropTable();
	delete m_pReferenceTable;

// {{ TCW_TERM_BASECLASS_CHECK2
	return(TCITableDefinition::Terminate());
} 	// }}
// }} TCW_TERMINATE_METHOD_END
// }} TCW_TC_PROTOTYPE_END


// {{ TCW_TC_PROTOTYPE(TCAddConstraint_CHECK)
//*-----------------------------------------------------------------------
//| Test Case:		TCAddConstraint_CHECK - Testcase for ITableDefinitionWithConstraints::AddConstraint used with DBCONSTRAINTTYPE_UNIQUE
//| Created:  	7/29/99
//*-----------------------------------------------------------------------

//*-----------------------------------------------------------------------
// @mfunc TestCase Initialization Routine
//
// @rdesc TRUE or FALSE
//
BOOL TCAddConstraint_CHECK::Init()
{ 
	// {{ TCW_INIT_BASECLASS_CHECK
	if(TCITableDefinition::Init())
	// }}
	{ 
		if (m_pITDWC == NULL)
		{
			odtLog << "ITableDefinitionWithConstraints is not supported.\n";
			return TEST_SKIPPED;
		}
		return TRUE;
	} 
	return FALSE;
} 




// {{ TCW_VAR_PROTOTYPE(1)
//*-----------------------------------------------------------------------
// @mfunc Add simple check constraint
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCAddConstraint_CHECK::Variation_1()
{ 
	TBEGIN
	HRESULT				hr;
	IRowsetChange		*pIRowsetChange	= NULL;
	CTable				Table(m_pThisTestModule->m_pIUnknown2, (LPWSTR)gwszModuleName);
	CCheckCons			cons;
	DBORDINAL			rgNULLCols[] = {1};
	CCol				col;

	TESTC_(Table.CreateTable(0, 0), S_OK);
	Table.AddInfoFromColumnsSchemaRowset(m_pITableDefinition, 
		Table.GetTableID().eKind? Table.GetTableID().uName.pwszName: NULL);

	// get the first column of the table
	cons.SetIsNotNULLCheckConstraint(&Table, rgNULLCols[0]);

	// add the constraint and check its addition
	TESTC_(AddConstraintAndCheck(m_pITDWC, &Table.GetTableID(), cons), S_OK);

	TEST2C_(hr = m_pIOpenRowset->OpenRowset(NULL, &Table.GetTableID(), NULL, 
		IID_IRowsetChange, 0, NULL, (IUnknown**)&pIRowsetChange), S_OK, E_NOINTERFACE);
	TESTC_PROVIDER(S_OK == hr);

	// try to insert a null value in a not null column
	TESTC_(hr = Insert(0, pIRowsetChange, NUMELEM(rgNULLCols), rgNULLCols), DB_E_INTEGRITYVIOLATION);

	TESTC_(Table.GetColInfo(rgNULLCols[0], col), S_OK);
	TEST2C_(hr = DropColumnAndCheck(&Table.GetTableID(), col.GetColID()), S_OK, DB_E_DROPRESTRICTED);

CLEANUP:
	SAFE_RELEASE(pIRowsetChange);
	Table.DropTable();
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END





// {{ TCW_VAR_PROTOTYPE(2)
//*-----------------------------------------------------------------------
// @mfunc Add 2 check constraints on the same column
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCAddConstraint_CHECK::Variation_2()
{ 
	TBEGIN
	CCheckCons			cons;
	DBORDINAL			indexCol = 1;
	CTable				Table(m_pThisTestModule->m_pIUnknown2, (LPWSTR)gwszModuleName);

	TESTC_(Table.CreateTable(0, 0), S_OK);
	Table.AddInfoFromColumnsSchemaRowset(m_pITDWC, Table.GetTableName());

	// get the first column of the table
	TESTC_(cons.SetIsNotNULLCheckConstraint(&Table, indexCol), S_OK);

	// add the constraint and check its addition
	TESTC_(AddConstraintAndCheck(m_pITDWC, &Table.GetTableID(), cons), S_OK);

	// change the name of the constraint helper object
	CHECK(cons.MakeConstraintName(), S_OK);
	
	// create the text of the constraint
	TESTC_(cons.SetLTCheckConstraint(&Table, indexCol, 2), S_OK);

	// add the constraint and check its addition
	TESTC_(AddConstraintAndCheck(m_pITDWC, &Table.GetTableID(), cons), S_OK);

CLEANUP:
	Table.DropTable();
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(3)
//*-----------------------------------------------------------------------
// @mfunc Add check constraint for each column
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCAddConstraint_CHECK::Variation_3()
{ 
	TBEGIN
	CTable				Table(m_pThisTestModule->m_pIUnknown2, (LPWSTR)gwszModuleName);
	CCheckCons			cons;
	CCol				col;
	DBORDINAL			indexCol;
	HRESULT				hrExpected = S_OK;

	TESTC_(Table.CreateTable(0, 0), S_OK);
	Table.AddInfoFromColumnsSchemaRowset(m_pITDWC, Table.GetTableName());

	for (indexCol = 0; indexCol < Table.CountColumnsOnTable(); indexCol++)
	{
		// get the first column of the table
		TESTC_(Table.GetColInfo(indexCol+1, col), S_OK);

		// change the name of the constraint helper object
		cons.SetConstraintName(col.GetColName());
		CHECK(cons.MakeConstraintName(), S_OK);
		
		// create the text of the constraint
		if (S_OK != cons.SetLTCheckConstraint(&Table, indexCol+1, 2))
			CHECK(cons.SetIsNotNULLCheckConstraint(&Table, indexCol+1), S_OK);

		// Check Constraints on BLOBs should fail
		if (col.GetIsLong())
			hrExpected = E_FAIL;
		else
			hrExpected = S_OK;

		odtLog << col.GetColName() << "\t -> " << (hrExpected==S_OK ? "S_OK" : "E_FAIL") << "\n";

		// add the constraint and check its addition
		CHECK(AddConstraintAndCheck(m_pITDWC, &Table.GetTableID(), cons), hrExpected);
	}

CLEANUP:
	Table.DropTable();
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(4)
//*-----------------------------------------------------------------------
// @mfunc Check constraint is always TRUE
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCAddConstraint_CHECK::Variation_4()
{ 
	TBEGIN
	CTable				Table(m_pThisTestModule->m_pIUnknown2, (LPWSTR)gwszModuleName);
	CCheckCons			cons(L"TRUE");
	CWString			wszText;
	CCol				col;

	TESTC_(Table.CreateTable(0, 0), S_OK);
	Table.AddInfoFromColumnsSchemaRowset(m_pITDWC, Table.GetTableName());

	// add the constraint and check its addition
	TESTC_(Table.GetColInfo(1, col), S_OK);
	wszText = col.GetColName();
	wszText + L" IS NULL OR ";
	wszText + col.GetColName();
	wszText + L" IS NOT NULL";
	cons.SetConstraintText((LPWSTR)(LPCWSTR)wszText);

	TESTC_(AddConstraintAndCheck(m_pITDWC, &Table.GetTableID(), cons), S_OK);

CLEANUP:
	Table.DropTable();
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(5)
//*-----------------------------------------------------------------------
// @mfunc Check constraint is always false
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCAddConstraint_CHECK::Variation_5()
{ 
	TBEGIN
	CTable				Table(m_pThisTestModule->m_pIUnknown2, (LPWSTR)gwszModuleName);
	CCheckCons			cons(L"FALSE");
	CWString			wszText;
	CCol				col;

	TESTC_(Table.CreateTable(0, 0), S_OK);
	Table.AddInfoFromColumnsSchemaRowset(m_pITDWC, Table.GetTableName());

	// add the constraint and check its addition
	TESTC_(Table.GetColInfo(1, col), S_OK);
	wszText = col.GetColName();
	wszText + L" IS NULL AND ";
	wszText + col.GetColName();
	wszText + L" IS NOT NULL";
	cons.SetConstraintText((LPWSTR)(LPCWSTR)wszText);

	TESTC_(AddConstraintAndCheck(m_pITDWC, &Table.GetTableID(), cons), S_OK);

CLEANUP:
	Table.DropTable();
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(6)
//*-----------------------------------------------------------------------
// @mfunc Long text for the check constraint
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCAddConstraint_CHECK::Variation_6()
{ 
	TBEGIN
	CTable				Table(m_pThisTestModule->m_pIUnknown2, (LPWSTR)gwszModuleName);
	CCheckCons			cons;
	const DBORDINAL		cTextLen = 1001;
	WCHAR				wszText[cTextLen];
	CCol				col;
	CWString			wszText1;

	TESTC_(Table.CreateTable(0, 0), S_OK);
	Table.AddInfoFromColumnsSchemaRowset(m_pITDWC, Table.GetTableName());

	TESTC_(Table.GetColInfo(1, col), S_OK);
	wszText1 = col.GetColName();
	wszText1 + L" IS NULL";

	swprintf(wszText, L"%1000s", (LPCWSTR)wszText1);
	cons.SetConstraintText(wszText);

	// add the constraint and check its addition
	TESTC_(AddConstraintAndCheck(m_pITDWC, &Table.GetTableID(), cons), S_OK);

CLEANUP:
	Table.DropTable();
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(7)
//*-----------------------------------------------------------------------
// @mfunc Check constraint is made of white characters
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCAddConstraint_CHECK::Variation_7()
{ 
	TBEGIN
	CTable				Table(m_pThisTestModule->m_pIUnknown2, (LPWSTR)gwszModuleName);
	CCheckCons			cons(L"  \t");

	TESTC_(Table.CreateTable(0, 0), S_OK);
	Table.AddInfoFromColumnsSchemaRowset(m_pITDWC, Table.GetTableName());

	// add the constraint and check its addition
	TESTC_(AddConstraintAndCheck(m_pITDWC, &Table.GetTableID(), cons), E_FAIL);

CLEANUP:
	Table.DropTable();
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(8)
//*-----------------------------------------------------------------------
// @mfunc Maximum length for the table name
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCAddConstraint_CHECK::Variation_8()
{ 
	TBEGIN
	CTable				Table(m_pThisTestModule->m_pIUnknown2, (LPWSTR)gwszModuleName);
	CCheckCons			cons;
	WCHAR				*pwszTableName		= NULL;

	// set a long table name
	m_pTable->MakeTableName(NULL);
	pwszTableName = BuildValidName(m_cMaxTableName, m_pTable->GetTableName());
	TESTC_(Table.CreateTable(0, 0, pwszTableName), S_OK);
	Table.AddInfoFromColumnsSchemaRowset(m_pITDWC, Table.GetTableName());

	// create the text of the constraint
	CHECK(cons.SetLTCheckConstraint(&Table, 1, 5), S_OK);

	// add the constraint and check its addition
	TESTC_(AddConstraintAndCheck(m_pITDWC, &Table.GetTableID(), cons), S_OK);

CLEANUP:
	SAFE_FREE(pwszTableName);
	Table.DropTable();
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(9)
//*-----------------------------------------------------------------------
// @mfunc Create the constraint, drop it, readd it with different text
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCAddConstraint_CHECK::Variation_9()
{ 
	TBEGIN
	CTable				Table(m_pThisTestModule->m_pIUnknown2, (LPWSTR)gwszModuleName);
	CCheckCons			cons;

	// create a table with an index
	TESTC_(Table.CreateTable(0, 1), S_OK);
	Table.AddInfoFromColumnsSchemaRowset(m_pITDWC, Table.GetTableName());

	// create the text of the constraint
	CHECK(cons.SetLTCheckConstraint(&Table, 1, 5), S_OK);

	// add the constraint and check its addition
	TESTC_(AddConstraintAndCheck(m_pITDWC, &Table.GetTableID(), cons), S_OK);

	TESTC_(DropConstraintAndCheck(m_pITDWC, &Table.GetTableID(), cons), S_OK);
	
	// set a different text
	CHECK(cons.SetIsNotNULLCheckConstraint(&Table, 2), S_OK);
	TESTC_(AddConstraintAndCheck(m_pITDWC, &Table.GetTableID(), cons), S_OK);

CLEANUP:
	Table.DropTable();
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(10)
//*-----------------------------------------------------------------------
// @mfunc Use inexistent column names in the check constraint
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCAddConstraint_CHECK::Variation_10()
{ 
	TBEGIN
	CTable				Table(m_pThisTestModule->m_pIUnknown2, (LPWSTR)gwszModuleName);
	CCheckCons			cons(L"InexistentCol < 10");
	CCol				col;

	// create a table with an index
	TESTC_(Table.CreateTable(0, 1), S_OK);
	Table.AddInfoFromColumnsSchemaRowset(m_pITDWC, Table.GetTableName());

	// add the constraint and check its addition
	TESTC_(AddConstraintAndCheck(m_pITDWC, &Table.GetTableID(), cons), DB_E_NOCOLUMN);

CLEANUP:
	Table.DropTable();
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(11)
//*-----------------------------------------------------------------------
// @mfunc Use qualified table column with different table
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCAddConstraint_CHECK::Variation_11()
{ 
	TBEGIN
	CTable				Table(m_pThisTestModule->m_pIUnknown2, (LPWSTR)gwszModuleName);
	CTable				Table2(m_pThisTestModule->m_pIUnknown2, (LPWSTR)gwszModuleName);
	CCheckCons			cons;
	CCol				col;
	WCHAR				*pwszColValue = NULL;
	CWString			wszText;
	HRESULT				hr = S_OK;
	DBCOLUMNDESC		*rgColumnDesc = NULL;

	// create a table with an index
	TESTC_(Table.CreateTable(0, 1), S_OK);
	Table.AddInfoFromColumnsSchemaRowset(m_pITDWC, Table.GetTableName());
	Table.BuildColumnDescs(&rgColumnDesc);
	
	//Second table should have the same columns' names
	Table2.SetColumnDesc(rgColumnDesc, Table.CountColumnsOnTable());
	Table2.SetBuildColumnDesc(FALSE);
	TESTC_(Table2.CreateTable(0, 1), S_OK);
	Table2.AddInfoFromColumnsSchemaRowset(m_pITDWC, Table2.GetTableName());

	// get the first column of the table
	TESTC_(Table2.GetColInfo(1 , col), S_OK);

	// create the text of the constraint
	TESTC_(Table.GetLiteralAndValue(col, &pwszColValue, rand(), col.GetColNum(), PRIMARY), S_OK);
	wszText = Table2.GetTableName();
	wszText + L".";
	wszText + col.GetColName();
	wszText + L" < ";
	wszText + pwszColValue;
	cons.SetConstraintText((LPWSTR)(LPCWSTR)wszText);

	// add the constraint and check its addition
	//Note: according to the spec provider can return E_FAIL or DB_E_NOCOLUMN when 
	//		column referenced by pwszConstraintText does not exist
	//		DB_E_BADCONSTRAINTFORM can not be retunred in this case
	//TESTC_(AddConstraintAndCheck(m_pITDWC, &Table.GetTableID(), cons), DB_E_BADCONSTRAINTFORM);
	TESTC_(AddConstraintAndCheck(m_pITDWC, &Table.GetTableID(), cons), DB_E_NOCOLUMN);

CLEANUP:
	SAFE_FREE(pwszColValue);
	Table.DropTable();
	Table2.DropTable();
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(12)
//*-----------------------------------------------------------------------
// @mfunc Set a check condition on an index column
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCAddConstraint_CHECK::Variation_12()
{ 
	TBEGIN
	CTable				Table(m_pThisTestModule->m_pIUnknown2, (LPWSTR)gwszModuleName);
	CCheckCons			cons;
	DBORDINAL			indexCol = 1;

	// create a table with an index
	TESTC_(Table.CreateTable(0, indexCol), S_OK);
	Table.AddInfoFromColumnsSchemaRowset(m_pITDWC, Table.GetTableName());

	CHECK(cons.SetLTCheckConstraint(&Table, indexCol, 7), S_OK);

	// add the constraint and check its addition
	TESTC_(AddConstraintAndCheck(m_pITDWC, &Table.GetTableID(), cons), S_OK);

CLEANUP:
	Table.DropTable();
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(13)
//*-----------------------------------------------------------------------
// @mfunc pwszConstraintText is NULL
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCAddConstraint_CHECK::Variation_13()
{ 
	TBEGIN
	CTable				Table(m_pThisTestModule->m_pIUnknown2, (LPWSTR)gwszModuleName);
	CCheckCons			cons;

	TESTC_(Table.CreateTable(0, 0), S_OK);
	Table.AddInfoFromColumnsSchemaRowset(m_pITDWC, Table.GetTableName());

	cons.SetConstraintText(NULL);

	// add the constraint and check its addition
	TESTC_(AddConstraintAndCheck(m_pITDWC, &Table.GetTableID(), cons), DB_E_BADCONSTRAINTFORM);

CLEANUP:
	Table.DropTable();
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(14)
//*-----------------------------------------------------------------------
// @mfunc pwszConstraintText is an empty string
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCAddConstraint_CHECK::Variation_14()
{ 
	TBEGIN
	CTable				Table(m_pThisTestModule->m_pIUnknown2, (LPWSTR)gwszModuleName);
	CCheckCons			cons(L"");

	TESTC_(Table.CreateTable(0, 0), S_OK);
	Table.AddInfoFromColumnsSchemaRowset(m_pITDWC, Table.GetTableName());

	// add the constraint and check its addition
	TESTC_(AddConstraintAndCheck(m_pITDWC, &Table.GetTableID(), cons), E_FAIL);

CLEANUP:
	Table.DropTable();
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(15)
//*-----------------------------------------------------------------------
// @mfunc Abort retaining
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCAddConstraint_CHECK::Variation_15()
{ 
	CAddCheckConsTxnAdapter	TxnAdapter(this);
	CTransactionLocal		TxnLocal;

	return TxnLocal.DoTransactionTest(m_pITDWC, &TxnAdapter,
		TRUE,		// DDL
		TRUE,		// Abort
		TRUE		// Retaining
		);
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(16)
//*-----------------------------------------------------------------------
// @mfunc Abort non retaining
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCAddConstraint_CHECK::Variation_16()
{ 
	CAddCheckConsTxnAdapter	TxnAdapter(this);
	CTransactionLocal		TxnLocal;

	return TxnLocal.DoTransactionTest(m_pITDWC, &TxnAdapter,
		TRUE,		// DDL
		TRUE,		// Abort
		FALSE		// Non Retaining
		);
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(17)
//*-----------------------------------------------------------------------
// @mfunc Commit retaining
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCAddConstraint_CHECK::Variation_17()
{ 
	CAddCheckConsTxnAdapter	TxnAdapter(this);
	CTransactionLocal		TxnLocal;

	return TxnLocal.DoTransactionTest(m_pITDWC, &TxnAdapter,
		TRUE,		// DDL
		FALSE,		// Commit
		TRUE		// Retaining
		);
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(18)
//*-----------------------------------------------------------------------
// @mfunc Commit non retaining
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCAddConstraint_CHECK::Variation_18()
{ 
	CAddCheckConsTxnAdapter	TxnAdapter(this);
	CTransactionLocal		TxnLocal;

	return TxnLocal.DoTransactionTest(m_pITDWC, &TxnAdapter,
		TRUE,		// DDL
		FALSE,		// Commit
		FALSE		// Non Retaining
		);
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(19)
//*-----------------------------------------------------------------------
// @mfunc Table is populated with rows that break the constraint to be added => DB_E_SCHEMAVIOLATION
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCAddConstraint_CHECK::Variation_19()
{ 
	TBEGIN
	HRESULT				hr;
	IRowsetChange		*pIRowsetChange	= NULL;
	CTable				Table(m_pThisTestModule->m_pIUnknown2, (LPWSTR)gwszModuleName);
	CCheckCons			cons;
	CCol				col;
	DBORDINAL			rgNULLCols[1];
	WCHAR				*pwszConstraintText = NULL;
	WCHAR				wszText[] = L" IS NOT NULL";

	TESTC_(Table.CreateTable(5, 0), S_OK);
	Table.AddInfoFromColumnsSchemaRowset(m_pITableDefinition, 
		Table.GetTableID().eKind? Table.GetTableID().uName.pwszName: NULL);

	// get the first column of the table
	TESTC_(Table.GetColInfo(1 , col), S_OK);
	SAFE_ALLOC(pwszConstraintText, WCHAR, 1 + wcslen(col.GetColName()) + wcslen(wszText));
	wcscpy(pwszConstraintText, col.GetColName());
	wcscat(pwszConstraintText, wszText);
	cons.SetConstraintText(pwszConstraintText);

	// add a row with a NULL first column
	TEST2C_(hr = m_pIOpenRowset->OpenRowset(NULL, &Table.GetTableID(), NULL, 
		IID_IRowsetChange, 0, NULL, (IUnknown**)&pIRowsetChange), S_OK, E_NOINTERFACE);
	TESTC_PROVIDER(S_OK == hr);

	// try to insert a null value in a not null column
	rgNULLCols[0] = col.GetColNum();
	TESTC_(hr = Insert(0, pIRowsetChange, NUMELEM(rgNULLCols), rgNULLCols), S_OK);

	// try to add the constraint 
	TESTC_(AddConstraintAndCheck(m_pITDWC, &Table.GetTableID(), cons), DB_E_SCHEMAVIOLATION);

CLEANUP:
	SAFE_RELEASE(pIRowsetChange);
	SAFE_FREE(pwszConstraintText);
	Table.DropTable();
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END

int TCAddConstraint_CHECK::Variation_20() {
	TBEGIN
	CTable					Table(m_pThisTestModule->m_pIUnknown2, (LPWSTR)gwszModuleName);
	CCheckCons				cons;
	DBCONSTRAINTDESC		*pConsDesc = (DBCONSTRAINTDESC*)cons;
	CCol					col;
	DBORDINAL				indxCat = 0;
	CCatalogs				Catalogs(m_pIOpenRowset);
	IDBProperties			*pIDBProperties = NULL;
	CPropSets				PropSets;
	WCHAR					*pwszCurrentCatalog = NULL;
	WCHAR					*pwszQualTableName = NULL;
	WCHAR					*pwszCatalogName = NULL;
	WCHAR					*pwszSchemaName = NULL;

	TESTC_PROVIDER(SettableProperty(DBPROP_CURRENTCATALOG, DBPROPSET_DATASOURCE, m_pIDBInitialize));
	TESTC_PROVIDER(1 < Catalogs.cCatalogs());

	// create a table and an index
	TESTC_(Table.CreateTable(0, 0), S_OK);
	Table.AddInfoFromColumnsSchemaRowset(m_pITDWC, Table.GetTableName());
	
	// select column
	TESTC_(Table.GetColInfo(1, col), S_OK);

	// set DBID of the table to its qualified form
	TESTC(DBKIND_NAME == Table.GetTableID().eKind);

	TESTC(GetCatalogSchemaNames(Table.GetTableName(), &pwszCatalogName, &pwszSchemaName));

	//Construct a fully Qualified TableName...
	TESTC_(m_pTable->GetQualifiedName(pwszCatalogName, pwszSchemaName, Table.GetTableName(), &pwszQualTableName),S_OK);
	Table.SetTableName(pwszQualTableName);

	// change the current catalog
	TESTC(GetProperty(DBPROP_CURRENTCATALOG, DBPROPSET_DATASOURCE, m_pIDBInitialize,
		&pwszCurrentCatalog));
	TESTC(NULL != pwszCurrentCatalog);

	TESTC(VerifyInterface(m_pIDBInitialize, IID_IDBProperties, DATASOURCE_INTERFACE, (IUnknown**)&pIDBProperties));

	if (0 == wcscmp(pwszCurrentCatalog, Catalogs[0]))
		indxCat++;

	CHECK(PropSets.AddProperty(DBPROP_CURRENTCATALOG, DBPROPSET_DATASOURCE, VT_BSTR, (LPVOID)Catalogs[indxCat]), S_OK);
	TESTC_PROVIDER(S_OK == pIDBProperties->SetProperties(PropSets, PropSets));

	// alloc memory for column array
	cons.SetIsNotNULLCheckConstraint(&Table, col.GetColNum());

	// try to make column unique
	TESTC_(AddConstraintAndCheck(m_pITDWC, &Table.GetTableID(), cons), S_OK);

CLEANUP:
	if (CHECK(PropSets.SetProperty(DBPROP_CURRENTCATALOG, DBPROPSET_DATASOURCE, VT_BSTR, (LPVOID)pwszCurrentCatalog), S_OK))
		CHECK(pIDBProperties->SetProperties(PropSets, PropSets), S_OK);

	SAFE_FREE(pwszCatalogName);
	SAFE_FREE(pwszSchemaName);
	SAFE_FREE(pwszQualTableName);
	SAFE_FREE(pwszCurrentCatalog);
	SAFE_RELEASE(pIDBProperties);
	Table.DropTable();
	TRETURN
}


// {{ TCW_TERMINATE_METHOD
//*-----------------------------------------------------------------------
// @mfunc TestCase Termination Routine 
//
// @rdesc TEST_PASS or TEST_FAIL 
//
BOOL TCAddConstraint_CHECK::Terminate()
{ 
	// TO DO:  Add your own code here 

// {{ TCW_TERM_BASECLASS_CHECK2
	return(TCITableDefinition::Terminate());
} 	// }}
// }} TCW_TERMINATE_METHOD_END
// }} TCW_TC_PROTOTYPE_END


// {{ TCW_TC_PROTOTYPE(TCAddConstraint_Deferrability)
//*-----------------------------------------------------------------------
//| Test Case:		TCAddConstraint_Deferrability - Testcase for ITableDefinitionWithConstraints::AddConstraint used with deferrability setting
//| Created:  	7/29/99
//*-----------------------------------------------------------------------

//*-----------------------------------------------------------------------
// @mfunc TestCase Initialization Routine
//
// @rdesc TRUE or FALSE
//
BOOL TCAddConstraint_Deferrability::Init()
{ 
	// {{ TCW_INIT_BASECLASS_CHECK
	if(TCITableDefinition::Init())
	// }}
	{ 
		if (m_pITDWC == NULL)
		{
			odtLog << "ITableDefinitionWithConstraints is not supported.\n";
			return TEST_SKIPPED;
		}
		return TRUE;
	} 
	return FALSE;
} 





// {{ TCW_VAR_PROTOTYPE(1)
//*-----------------------------------------------------------------------
// @mfunc Immediate unique constraint
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCAddConstraint_Deferrability::Variation_1()
{ 
	TBEGIN
	CTable	Table(m_pITDWC, (LPWSTR)gwszModuleName);

	// create a table
	TESTC_(Table.CreateTable(3, 0), S_OK);
	Table.AddInfoFromColumnsSchemaRowset(m_pITDWC, Table.GetTableName());

	// create an immediate unique constraint
	TESTC_(AddUniqueConstraint(&Table, 1, (DBDEFERRABILITY)0), S_OK);
	
	// check that adding row with seed 2 again will fail
	TESTC_(Table.Insert(2), DB_E_INTEGRITYVIOLATION);

CLEANUP:
	Table.DropTable();
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(2)
//*-----------------------------------------------------------------------
// @mfunc Defferable unique constraint
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCAddConstraint_Deferrability::Variation_2()
{ 
	TBEGIN
	HRESULT	hr;
	CTable	Table(m_pITDWC, (LPWSTR)gwszModuleName);

	// create a table
	TESTC_(Table.CreateTable(3, 0), S_OK);
	Table.AddInfoFromColumnsSchemaRowset(m_pITDWC, Table.GetTableName());

	// create a deferrable unique constraint
	TEST2C_(hr = AddUniqueConstraint(&Table, 1, DBDEFERRABILITY_DEFERRABLE), S_OK, DB_E_BADDEFERRABILITY);
	
	// check that adding row with seed 2 again will fail
	if (S_OK == hr)
	{
		TESTC_(Table.Insert(2), DB_E_INTEGRITYVIOLATION);
	}
	else
		odtLog << "Deferrable unique constraints are not supported\n";

CLEANUP:
	Table.DropTable();
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(3)
//*-----------------------------------------------------------------------
// @mfunc Deffered unique constraint
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCAddConstraint_Deferrability::Variation_3()
{ 
	TBEGIN
	HRESULT	hr;
	CTable	Table(m_pITDWC, (LPWSTR)gwszModuleName);

	// create a table
	TESTC_(Table.CreateTable(3, 0), S_OK);
	Table.AddInfoFromColumnsSchemaRowset(m_pITDWC, Table.GetTableName());

	// create an deferred unique constraint
	TEST2C_(hr = AddUniqueConstraint(&Table, 1, 
		DBDEFERRABILITY_DEFERRABLE | DBDEFERRABILITY_DEFERRED), S_OK, DB_E_BADDEFERRABILITY);
	
	// check that adding row with seed 2 again will fail
	if (S_OK == hr)
	{
		TESTC_(Table.Insert(2), DB_E_INTEGRITYVIOLATION);
	}
	else
		odtLog << "Deferred unique constraints are not supported\n";

CLEANUP:
	Table.DropTable();
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(4)
//*-----------------------------------------------------------------------
// @mfunc Bad deferrability value unique constraint
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCAddConstraint_Deferrability::Variation_4()
{ 
	TBEGIN
	CTable	Table(m_pITDWC, (LPWSTR)gwszModuleName);

	// create a table
	TESTC_(Table.CreateTable(0), S_OK);
	Table.AddInfoFromColumnsSchemaRowset(m_pITDWC, Table.GetTableName());

	// create a unique constraint
	TESTC_(AddUniqueConstraint(&Table, 1, 
		~(DBDEFERRABILITY_DEFERRABLE | DBDEFERRABILITY_DEFERRED)), DB_E_BADDEFERRABILITY);
	
CLEANUP:
	Table.DropTable();
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(5)
//*-----------------------------------------------------------------------
// @mfunc Immediate primary key constraint
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCAddConstraint_Deferrability::Variation_5()
{ 
	TBEGIN
	CTable	Table(m_pITDWC, (LPWSTR)gwszModuleName);

	// create a table
	TESTC_(CreateTableWithNoNullableColumns(&Table, 3), S_OK);

	// create an immediate unique constraint
	TESTC_(AddPrimaryKeyConstraint(&Table, 1, (DBDEFERRABILITY)0), S_OK);
	
	// check that adding row with seed 2 again will fail
	TESTC_(Table.Insert(2), DB_E_INTEGRITYVIOLATION);

CLEANUP:
	Table.DropTable();
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(6)
//*-----------------------------------------------------------------------
// @mfunc Deferrable primary key constraint
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCAddConstraint_Deferrability::Variation_6()
{ 
	TBEGIN
	HRESULT	hr;
	CTable	Table(m_pITDWC, (LPWSTR)gwszModuleName);

	// create a table
	TESTC_(CreateTableWithNoNullableColumns(&Table, 3), S_OK);

	// create a deferrable unique constraint
	TEST2C_(hr = AddPrimaryKeyConstraint(&Table, 1, DBDEFERRABILITY_DEFERRABLE), S_OK, DB_E_BADDEFERRABILITY);
	
	// check that adding row with seed 2 again will fail
	if (S_OK == hr)
	{
		TESTC_(Table.Insert(2), DB_E_INTEGRITYVIOLATION);
	}
	else
		odtLog << "Deferrable primary key constraints are not supported\n";

CLEANUP:
	Table.DropTable();
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(7)
//*-----------------------------------------------------------------------
// @mfunc Deferred primary key constraint
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCAddConstraint_Deferrability::Variation_7()
{ 
	TBEGIN
	HRESULT	hr;
	CTable	Table(m_pITDWC, (LPWSTR)gwszModuleName);

	// create a table
	TESTC_(CreateTableWithNoNullableColumns(&Table, 3), S_OK);

	// create an deferred primary key constraint
	TEST2C_(hr = AddPrimaryKeyConstraint(&Table, 1, 
		DBDEFERRABILITY_DEFERRABLE | DBDEFERRABILITY_DEFERRED), S_OK, DB_E_BADDEFERRABILITY);
	
	// check that adding row with seed 2 again will fail
	if (S_OK == hr)
	{
		TESTC_(Table.Insert(2), DB_E_INTEGRITYVIOLATION);
	}
	else
		odtLog << "Deferred primary key constraints are not supported\n";

CLEANUP:
	Table.DropTable();
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(8)
//*-----------------------------------------------------------------------
// @mfunc Bad deferrability value primary key constraint
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCAddConstraint_Deferrability::Variation_8()
{ 
	TBEGIN
	CTable	Table(m_pITDWC, (LPWSTR)gwszModuleName);

	// create a table
	TESTC_(CreateTableWithNoNullableColumns(&Table, 0), S_OK);

	// create a primary key  constraint
	TESTC_(AddPrimaryKeyConstraint(&Table, 1, 
		~(DBDEFERRABILITY_DEFERRABLE | DBDEFERRABILITY_DEFERRED)), DB_E_BADDEFERRABILITY);
	
CLEANUP:
	Table.DropTable();
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(9)
//*-----------------------------------------------------------------------
// @mfunc Immediate foreign key constraint
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCAddConstraint_Deferrability::Variation_9()
{ 
	TBEGIN
	CTable		BaseTable(m_pITDWC, (LPWSTR)gwszModuleName);
	CTable		ReferencedTable(m_pITDWC, (LPWSTR)gwszModuleName);
	DBORDINAL	rgBaseCol[]			= {1};
	DBORDINAL	rgReferencedCol[]	= {1};

	// create a table
	TESTC_(BaseTable.CreateTable(0), S_OK);
	BaseTable.AddInfoFromColumnsSchemaRowset(m_pITDWC, BaseTable.GetTableName());
	TESTC_(ReferencedTable.CreateTable(0), S_OK);
	ReferencedTable.AddInfoFromColumnsSchemaRowset(m_pITDWC, ReferencedTable.GetTableName());

	// create a unique constraint in the refereced table
	TESTC_PROVIDER(S_OK == AddUniqueConstraint(&ReferencedTable, 1));

	// create an immediate foreign key constraint
	TESTC_(AddForeignKeyConstraint(&BaseTable, NUMELEM(rgBaseCol), rgBaseCol,
		&ReferencedTable, NUMELEM(rgReferencedCol), rgReferencedCol, 
		m_SupportedMatchType, DBUPDELRULE_NOACTION, DBUPDELRULE_NOACTION,
		(DBDEFERRABILITY)0), S_OK);
	
	// check that adding row with seed 2 again will fail
	TESTC_(BaseTable.Insert(10), DB_E_INTEGRITYVIOLATION);

	// check adding row in the referenced table is ok
	TESTC_(ReferencedTable.Insert(10), S_OK);
	TESTC_(BaseTable.Insert(10), S_OK);

CLEANUP:
	BaseTable.DropTable();
	ReferencedTable.DropTable();
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(10)
//*-----------------------------------------------------------------------
// @mfunc Deferrable foreign key constraint
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCAddConstraint_Deferrability::Variation_10()
{ 
	TBEGIN
	HRESULT		hr;
	CTable		BaseTable(m_pITDWC, (LPWSTR)gwszModuleName);
	CTable		ReferencedTable(m_pITDWC, (LPWSTR)gwszModuleName);
	DBORDINAL	rgBaseCol[]			= {1};
	DBORDINAL	rgReferencedCol[]	= {1};

	// create a table
	TESTC_(BaseTable.CreateTable(0), S_OK);
	BaseTable.AddInfoFromColumnsSchemaRowset(m_pITDWC, BaseTable.GetTableName());
	TESTC_(ReferencedTable.CreateTable(0), S_OK);
	ReferencedTable.AddInfoFromColumnsSchemaRowset(m_pITDWC, ReferencedTable.GetTableName());

	// create a unique constraint in the refereced table
	TESTC_PROVIDER(S_OK == AddUniqueConstraint(&ReferencedTable, 1));

	// create a deferrable foreign key constraint
	TEST2C_(hr = AddForeignKeyConstraint(&BaseTable, NUMELEM(rgBaseCol), rgBaseCol,
		&ReferencedTable, NUMELEM(rgReferencedCol), rgReferencedCol, 
		m_SupportedMatchType, DBUPDELRULE_NOACTION, DBUPDELRULE_NOACTION,
		DBDEFERRABILITY_DEFERRABLE), S_OK, DB_E_BADDEFERRABILITY);

	if (S_OK == hr)
	{
		// check that adding row with seed 2 again will fail
		TESTC_(BaseTable.Insert(2), DB_E_INTEGRITYVIOLATION);

		// check adding row in the referenced table is ok
		TESTC_(ReferencedTable.Insert(2), S_OK);
		TESTC_(BaseTable.Insert(2), S_OK);
	}
	else
		odtLog << "Deferrable foreign key not supported\n";

CLEANUP:
	BaseTable.DropTable();
	ReferencedTable.DropTable();
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(11)
//*-----------------------------------------------------------------------
// @mfunc Deferred foreign key constraint
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCAddConstraint_Deferrability::Variation_11()
{ 
	TBEGIN
	HRESULT		hr;
	CTable		BaseTable(m_pITDWC, (LPWSTR)gwszModuleName);
	CTable		ReferencedTable(m_pITDWC, (LPWSTR)gwszModuleName);
	DBORDINAL	rgBaseCol[]			= {1};
	DBORDINAL	rgReferencedCol[]	= {1};

	// create a table
	TESTC_(BaseTable.CreateTable(0), S_OK);
	BaseTable.AddInfoFromColumnsSchemaRowset(m_pITDWC, BaseTable.GetTableName());
	TESTC_(ReferencedTable.CreateTable(0), S_OK);
	ReferencedTable.AddInfoFromColumnsSchemaRowset(m_pITDWC, ReferencedTable.GetTableName());

	// create a unique constraint in the refereced table
	TESTC_PROVIDER(S_OK == AddUniqueConstraint(&ReferencedTable, 1));

	// create a deferrable foreign key constraint
	TEST2C_(hr = AddForeignKeyConstraint(&BaseTable, NUMELEM(rgBaseCol), rgBaseCol,
		&ReferencedTable, NUMELEM(rgReferencedCol), rgReferencedCol, 
		m_SupportedMatchType, DBUPDELRULE_NOACTION, DBUPDELRULE_NOACTION,
		DBDEFERRABILITY_DEFERRABLE | DBDEFERRABILITY_DEFERRED), 
		S_OK, DB_E_BADDEFERRABILITY);
	
	if (S_OK == hr)
	{
		// check that adding row with seed 2 again will fail
		TESTC_(BaseTable.Insert(2), S_OK);

		// check adding row in the referenced table is ok
		TESTC_(ReferencedTable.Insert(2), S_OK);
		TESTC_(BaseTable.Insert(2), S_OK);
	}
	else
		odtLog << "Deferred foreign key not supported\n";

CLEANUP:
	BaseTable.DropTable();
	ReferencedTable.DropTable();
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(12)
//*-----------------------------------------------------------------------
// @mfunc Bad deferrability value foreign key constraint
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCAddConstraint_Deferrability::Variation_12()
{ 
	TBEGIN
	CTable		BaseTable(m_pITDWC, (LPWSTR)gwszModuleName);
	CTable		ReferencedTable(m_pITDWC, (LPWSTR)gwszModuleName);
	DBORDINAL	rgBaseCol[]			= {1};
	DBORDINAL	rgReferencedCol[]	= {1};

	// create a table
	TESTC_(BaseTable.CreateTable(0), S_OK);
	BaseTable.AddInfoFromColumnsSchemaRowset(m_pITDWC, BaseTable.GetTableName());
	TESTC_(ReferencedTable.CreateTable(0), S_OK);
	ReferencedTable.AddInfoFromColumnsSchemaRowset(m_pITDWC, ReferencedTable.GetTableName());

	// create a unique constraint in the refereced table
	TESTC_PROVIDER(S_OK == AddUniqueConstraint(&ReferencedTable, 1));

	// create an immediate foreign key constraint
	TESTC_(AddForeignKeyConstraint(&BaseTable, NUMELEM(rgBaseCol), rgBaseCol,
		&ReferencedTable, NUMELEM(rgReferencedCol), rgReferencedCol, 
		m_SupportedMatchType, DBUPDELRULE_NOACTION, DBUPDELRULE_NOACTION,
		~(DBDEFERRABILITY_DEFERRABLE | DBDEFERRABILITY_DEFERRED)), DB_E_BADDEFERRABILITY);
	
	// check adding row in the referenced table is ok
	TESTC_(ReferencedTable.Insert(2), S_OK);

CLEANUP:
	BaseTable.DropTable();
	ReferencedTable.DropTable();
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(13)
//*-----------------------------------------------------------------------
// @mfunc Immediate check constraint
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCAddConstraint_Deferrability::Variation_13()
{ 
	TBEGIN
	CTable				Table(m_pThisTestModule->m_pIUnknown2, (LPWSTR)gwszModuleName);
	CCheckCons			cons;
	CCol				col;
	WCHAR				*pwszConstraintText = NULL;
	WCHAR				wszText[] = L" IS NULL";

	TESTC_(Table.CreateTable(0, 0), S_OK);
	Table.AddInfoFromColumnsSchemaRowset(m_pITDWC, Table.GetTableName());

	// get the first column of the table
	TESTC_(Table.GetColInfo(1 , col), S_OK);
	SAFE_ALLOC(pwszConstraintText, WCHAR, 1 + wcslen(col.GetColName()) + wcslen(wszText));
	wcscpy(pwszConstraintText, col.GetColName());
	wcscat(pwszConstraintText, wszText);
	cons.SetConstraintText(pwszConstraintText);
	cons.SetDeferrability((DBDEFERRABILITY)0);

	// add the constraint and check its addition
	TESTC_(AddConstraintAndCheck(m_pITDWC, &Table.GetTableID(), cons), S_OK);

	// add a row that does not have NULL in the checked column
	TESTC_PROVIDER(2 < Table.CountColumnsOnTable());
	TESTC_(Table.Insert(3), DB_E_INTEGRITYVIOLATION);

CLEANUP:
	SAFE_FREE(pwszConstraintText);
	Table.DropTable();
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(14)
//*-----------------------------------------------------------------------
// @mfunc Deferrable check constraint
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCAddConstraint_Deferrability::Variation_14()
{ 
	TBEGIN
	HRESULT			hr;
	CTable			Table(m_pThisTestModule->m_pIUnknown2, (LPWSTR)gwszModuleName);
	CCheckCons		cons;
	CCol			col;
	WCHAR			*pwszConstraintText = NULL;
	WCHAR			wszText[] = L" IS NULL";

	TESTC_(Table.CreateTable(0, 0), S_OK);
	Table.AddInfoFromColumnsSchemaRowset(m_pITDWC, Table.GetTableName());

	// get the first column of the table
	TESTC_(Table.GetColInfo(1 , col), S_OK);
	SAFE_ALLOC(pwszConstraintText, WCHAR, 1 + wcslen(col.GetColName()) + wcslen(wszText));
	wcscpy(pwszConstraintText, col.GetColName());
	wcscat(pwszConstraintText, wszText);
	cons.SetConstraintText(pwszConstraintText);
	cons.SetDeferrability(DBDEFERRABILITY_DEFERRABLE);

	// add the constraint and check its addition
	TEST2C_(hr = AddConstraintAndCheck(m_pITDWC, &Table.GetTableID(), cons), S_OK, DB_E_BADDEFERRABILITY);

	if (S_OK == hr)
	{
	// add a row that does not have NULL in the checked column
	TESTC_PROVIDER(2 < Table.CountColumnsOnTable());
	TESTC_(Table.Insert(3), DB_E_INTEGRITYVIOLATION);
	}
	else
		odtLog << "Deferrable check constraints are not supported\n";

CLEANUP:
	SAFE_FREE(pwszConstraintText);
	Table.DropTable();
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(15)
//*-----------------------------------------------------------------------
// @mfunc Deferred check constraint
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCAddConstraint_Deferrability::Variation_15()
{ 
	TBEGIN
	HRESULT			hr;
	CTable			Table(m_pThisTestModule->m_pIUnknown2, (LPWSTR)gwszModuleName);
	CCheckCons		cons;
	CCol			col;
	WCHAR			*pwszConstraintText = NULL;
	WCHAR			wszText[] = L" IS NULL";

	TESTC_(Table.CreateTable(0, 0), S_OK);
	Table.AddInfoFromColumnsSchemaRowset(m_pITDWC, Table.GetTableName());

	// get the first column of the table
	TESTC_(Table.GetColInfo(1 , col), S_OK);
	SAFE_ALLOC(pwszConstraintText, WCHAR, 1 + wcslen(col.GetColName()) + wcslen(wszText));
	wcscpy(pwszConstraintText, col.GetColName());
	wcscat(pwszConstraintText, wszText);
	cons.SetConstraintText(pwszConstraintText);
	cons.SetDeferrability(DBDEFERRABILITY_DEFERRABLE | DBDEFERRABILITY_DEFERRED);

	// add the constraint and check its addition
	TEST2C_(hr = AddConstraintAndCheck(m_pITDWC, &Table.GetTableID(), cons), S_OK, DB_E_BADDEFERRABILITY);

	if (S_OK == hr)
	{
		// add a row that does not have NULL in the checked column
		TESTC_(Table.Insert(3), S_OK);
	}
	else
		odtLog << "Deferred check constraints are not supported\n";

CLEANUP:
	SAFE_FREE(pwszConstraintText);
	Table.DropTable();
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(16)
//*-----------------------------------------------------------------------
// @mfunc Bad deferrability value check constraint
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCAddConstraint_Deferrability::Variation_16()
{ 
	TBEGIN
	CTable			Table(m_pThisTestModule->m_pIUnknown2, (LPWSTR)gwszModuleName);
	CCheckCons		cons;
	CCol			col;
	WCHAR			*pwszConstraintText = NULL;
	WCHAR			wszText[] = L" IS NULL";

	TESTC_(Table.CreateTable(0, 0), S_OK);
	Table.AddInfoFromColumnsSchemaRowset(m_pITDWC, Table.GetTableName());

	// get the first column of the table
	TESTC_(Table.GetColInfo(1 , col), S_OK);
	SAFE_ALLOC(pwszConstraintText, WCHAR, 1 + wcslen(col.GetColName()) + wcslen(wszText));
	wcscpy(pwszConstraintText, col.GetColName());
	wcscat(pwszConstraintText, wszText);
	cons.SetConstraintText(pwszConstraintText);
	cons.SetDeferrability(~(DBDEFERRABILITY_DEFERRABLE | DBDEFERRABILITY_DEFERRED));

	// add the constraint and check its addition
	TESTC_(AddConstraintAndCheck(m_pITDWC, &Table.GetTableID(), cons), DB_E_BADDEFERRABILITY);

CLEANUP:
	SAFE_FREE(pwszConstraintText);
	Table.DropTable();
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END


// {{ TCW_TERMINATE_METHOD
//*-----------------------------------------------------------------------
// @mfunc TestCase Termination Routine 
//
// @rdesc TEST_PASS or TEST_FAIL 
//
BOOL TCAddConstraint_Deferrability::Terminate()
{ 
	// TO DO:  Add your own code here 

// {{ TCW_TERM_BASECLASS_CHECK2
	return(TCITableDefinition::Terminate());
} 	// }}
// }} TCW_TERMINATE_METHOD_END
// }} TCW_TC_PROTOTYPE_END


// {{ TCW_TC_PROTOTYPE(TCCreateTableWithConstraints_NoConstraint)
//*-----------------------------------------------------------------------
//| Test Case:		TCCreateTableWithConstraints_NoConstraint - Testcase for ITableDefinitionWithConstraints::AddConstraint used with deferrability setting
//| Created:  	7/29/99
//*-----------------------------------------------------------------------

//*-----------------------------------------------------------------------
// @mfunc TestCase Initialization Routine
//
// @rdesc TRUE or FALSE
//
BOOL TCCreateTableWithConstraints_NoConstraint::Init()
{ 
	ITableDefinitionWithConstraints	*pITableDefinitionWithConstraints	= NULL;

	if(TCCreateTable::Init())
	{
		// check for ITableDefinition
		if (!(m_hr=VerifyInterface(m_pIOpenRowset, IID_ITableDefinitionWithConstraints, SESSION_INTERFACE, (IUnknown**)&pITableDefinitionWithConstraints)))
		{
			odtLog << "ITableDefinitionWithConstraints is not supported\n";
			return TEST_SKIPPED;
		}

		SAFE_RELEASE(pITableDefinitionWithConstraints);
		return TRUE;
	}
	return FALSE;
} 



//---------------------------------------------------------------------
//
// @member Create the table using ITableDefinition::CreateTable and 
// check its creation
//---------------------------------------------------------------------
HRESULT	TCCreateTableWithConstraints_NoConstraint::CreateAndCheckTable(
	ITableDefinition	*pITableDefinition,	// [in] pointer to the ITableDefinition interface to be used
	IUnknown			*pUnkOuter,			// [in] pointer to controlling unknown
	DBID				*pTableID,			// [in]	pointer to the input table ID
	DBORDINAL			cColumnDescs,		// [in]	the number of columns to be created
	DBCOLUMNDESC		*rgColumnDescs,		// [in/out] array of columns to be created
	REFIID				riid,				// [in] rowset interface to be returned
	ULONG				cPropertySets,		// [in] number of roset property sets asked
	DBPROPSET			*rgPropertySets,	// [in/out] array of rowset property sets
	DBID				**ppTableID,		// [out] returned table ID
	IUnknown			**ppRowset			// [out] pointer to outer interface
)
{
	HRESULT								hr		= E_FAIL;
	ITableDefinitionWithConstraints		*pITDWC = NULL;

	TESTC(NULL != pITableDefinition);
	TESTC(VerifyInterface(pITableDefinition, IID_ITableDefinitionWithConstraints, 
		SESSION_INTERFACE, (IUnknown**)&pITDWC));

	hr = CreateAndCheckTableWithConstraints(pITDWC, pUnkOuter, pTableID,
		cColumnDescs, rgColumnDescs, 0, NULL, 
		riid, cPropertySets, rgPropertySets,
		ppTableID, ppRowset);

CLEANUP:
	SAFE_RELEASE(pITDWC);
	return hr;
} //TCCreateTableWithConstraints_NoConstraint::CreateAndCheckTable



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


// {{ TCW_TC_PROTOTYPE(TCCreateTableWithConstraints)
//*-----------------------------------------------------------------------
//| Test Case:		TCCreateTableWithConstraints - Testcase for ITableDefinitionWithConstraints::CreateTableWithConstraints when constraints are set
//| Created:  	7/29/99
//*-----------------------------------------------------------------------

//*-----------------------------------------------------------------------
// @mfunc TestCase Initialization Routine
//
// @rdesc TRUE or FALSE
//
BOOL TCCreateTableWithConstraints::Init()
{ 
	// {{ TCW_INIT_BASECLASS_CHECK
	if(TCITableDefinition::Init())
	// }}
	{ 
		if (m_pITDWC == NULL)
		{
			odtLog << "ITableDefinitionWithConstraints is not supported.\n";
			return TEST_SKIPPED;
		}
		return TRUE;
	} 
	return FALSE;
} 




// {{ TCW_VAR_PROTOTYPE(1)
//*-----------------------------------------------------------------------
// @mfunc Create a table and multiple constraint of various types
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCCreateTableWithConstraints::Variation_1()
{ 
	TBEGIN
	CTable			ReferencedTable(m_pThisTestModule->m_pIUnknown2, (LPWSTR)gwszModuleName);
	DBID			TableID;
	DBCOLUMNDESC	*rgColumnDesc	= NULL;
	DBORDINAL		cColumnDesc		= 0;
	CConsDescArray	ConsDescArray;
	CUniqueCons		consUnique;
	CPrimaryKeyCons	consPrimaryKey;
	CForeignKeyCons	consForeignKey(NULL, m_SupportedMatchType);
	DBORDINAL		rgReferencedCol[] = {1};
	CCol			col;

	DuplicateColumnDesc(m_rgColumnDesc, m_cColumnDesc, &rgColumnDesc);
	cColumnDesc = m_cColumnDesc;
	// release the properties on all column and make the first column not nullable
	ReleaseAllColumnPropSets(rgColumnDesc, cColumnDesc);
	SetProperty(&rgColumnDesc[0].rgPropertySets, &rgColumnDesc[0].cPropertySets,
			DBPROP_COL_NULLABLE, 
			VT_BOOL, (LPVOID)VARIANT_FALSE, 
			DBPROPOPTIONS_REQUIRED);

	m_pTable->MakeTableName(NULL);
	TableID.eKind			= DBKIND_NAME;
	TableID.uName.pwszName	= m_pTable->GetTableName();

	// create support for foreign key constraint
	TESTC_(ReferencedTable.CreateTable(0, 0), S_OK);
	ReferencedTable.AddInfoFromColumnsSchemaRowset(m_pITDWC, ReferencedTable.GetTableName());
	// make the referenced columns unique
	TESTC_(AddUniqueConstraint(&ReferencedTable, rgReferencedCol[0], (DBDEFERRABILITY)0), S_OK);

	// set a unique constraint on the second column
	consUnique.AddColumn(&rgColumnDesc[1].dbcid);

	// set a primary key on the first column of the table
	consPrimaryKey.AddColumn(&rgColumnDesc[0].dbcid);

	// set a simple foreign key constraint
	TESTC_(ReferencedTable.GetColInfo(1, col), S_OK);
	consForeignKey.AddColumn(col.GetColID());
	consForeignKey.AddForeignKeyColumn(&rgColumnDesc[0].dbcid);
	consForeignKey.SetReferencedTableID(&ReferencedTable.GetTableID());

	// add all constraint to the array
	ConsDescArray.AddConsDesc(consUnique);
	ConsDescArray.AddConsDesc(consForeignKey);
	ConsDescArray.AddConsDesc(consPrimaryKey);

	TESTC_(CreateAndCheckTableWithConstraints(m_pITDWC, NULL, &TableID, cColumnDesc, rgColumnDesc, 
		ConsDescArray, ConsDescArray, 
		IID_IRowset, 0, NULL, NULL, NULL), S_OK);
	
CLEANUP:
	CHECK(DropTableAndCheck(&TableID), S_OK);
	CHECK(ReferencedTable.DropTable(), S_OK);
	ReleaseColumnDesc(rgColumnDesc, cColumnDesc);
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END





// {{ TCW_VAR_PROTOTYPE(2)
//*-----------------------------------------------------------------------
// @mfunc Table with a unique constraint (on a single column)
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCCreateTableWithConstraints::Variation_2()
{ 
	TBEGIN
	DBID			TableID;
	DBCOLUMNDESC	*rgColumnDesc	= NULL;
	DBORDINAL		cColumnDesc		= 0;
	CUniqueCons		consUnique;

	DuplicateColumnDesc(m_rgColumnDesc, m_cColumnDesc, &rgColumnDesc);
	cColumnDesc = m_cColumnDesc;

	m_pTable->MakeTableName(NULL);
	TableID.eKind			= DBKIND_NAME;
	TableID.uName.pwszName	= m_pTable->GetTableName();

	// set a unique constraint on the second column
	consUnique.AddColumn(&rgColumnDesc[0].dbcid);

	TESTC_(CreateAndCheckTableWithConstraints(m_pITDWC, NULL, &TableID, cColumnDesc, rgColumnDesc, 
		1, consUnique, 
		IID_IRowset, 0, NULL, NULL, NULL), S_OK);
	
CLEANUP:
	CHECK(DropTableAndCheck(&TableID), S_OK);
	ReleaseColumnDesc(rgColumnDesc, cColumnDesc);
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(3)
//*-----------------------------------------------------------------------
// @mfunc Table with a unique constraint (on multiple columns)
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCCreateTableWithConstraints::Variation_3()
{ 
	TBEGIN
	DBID			TableID;
	DBCOLUMNDESC	*rgColumnDesc	= NULL;
	DBORDINAL		cColumnDesc		= 0;
	CUniqueCons		consUnique;

	DuplicateColumnDesc(m_rgColumnDesc, m_cColumnDesc, &rgColumnDesc);
	cColumnDesc = m_cColumnDesc;

	m_pTable->MakeTableName(NULL);
	TableID.eKind			= DBKIND_NAME;
	TableID.uName.pwszName	= m_pTable->GetTableName();

	// set a unique constraint on the second column
	consUnique.AddColumn(&rgColumnDesc[0].dbcid);
	consUnique.AddColumn(&rgColumnDesc[3].dbcid);
	consUnique.AddColumn(&rgColumnDesc[1].dbcid);

	TESTC_(CreateAndCheckTableWithConstraints(m_pITDWC, NULL, &TableID, cColumnDesc, rgColumnDesc, 
		1, consUnique, 
		IID_IRowset, 0, NULL, NULL, NULL), S_OK);
	
CLEANUP:
	CHECK(DropTableAndCheck(&TableID), S_OK);
	ReleaseColumnDesc(rgColumnDesc, cColumnDesc);
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(4)
//*-----------------------------------------------------------------------
// @mfunc Table with a primary key constraint (on a single column)
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCCreateTableWithConstraints::Variation_4()
{ 
	TBEGIN
	DBID				TableID;
	DBCOLUMNDESC		*rgColumnDesc	= NULL;
	DBORDINAL			cColumnDesc		= 0;
	CPrimaryKeyCons		consPK;

	DuplicateColumnDesc(m_rgColumnDesc, m_cColumnDesc, &rgColumnDesc);
	cColumnDesc = m_cColumnDesc;
	// release the properties on all column and make the first column not nullable
	ReleaseAllColumnPropSets(rgColumnDesc, cColumnDesc);
	SetProperty(&rgColumnDesc[0].rgPropertySets, &rgColumnDesc[0].cPropertySets,
			DBPROP_COL_NULLABLE, 
			VT_BOOL, (LPVOID)VARIANT_FALSE, 
			DBPROPOPTIONS_REQUIRED);

	m_pTable->MakeTableName(NULL);
	TableID.eKind			= DBKIND_NAME;
	TableID.uName.pwszName	= m_pTable->GetTableName();

	// set a primary key constraint on the second column
	consPK.AddColumn(&rgColumnDesc[0].dbcid);

	TESTC_(CreateAndCheckTableWithConstraints(m_pITDWC, NULL, &TableID, cColumnDesc, rgColumnDesc, 
		1, consPK, 
		IID_IRowset, 0, NULL, NULL, NULL), S_OK);
	
CLEANUP:
	CHECK(DropTableAndCheck(&TableID), S_OK);
	ReleaseColumnDesc(rgColumnDesc, cColumnDesc);
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(5)
//*-----------------------------------------------------------------------
// @mfunc Table with a primary key constraint (on multiple columns)
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCCreateTableWithConstraints::Variation_5()
{ 
	TBEGIN
	DBID				TableID;
	DBCOLUMNDESC		*rgColumnDesc	= NULL;
	DBORDINAL			cColumnDesc		= 0;
	CPrimaryKeyCons		consPK;

	DuplicateColumnDesc(m_rgColumnDesc, m_cColumnDesc, &rgColumnDesc);
	cColumnDesc = m_cColumnDesc;
	// release the properties on all column and make the first column not nullable
	ReleaseAllColumnPropSets(rgColumnDesc, cColumnDesc);
	SetProperty(&rgColumnDesc[0].rgPropertySets, &rgColumnDesc[0].cPropertySets,
			DBPROP_COL_NULLABLE, 
			VT_BOOL, (LPVOID)VARIANT_FALSE, 
			DBPROPOPTIONS_REQUIRED);

	m_pTable->MakeTableName(NULL);
	TableID.eKind			= DBKIND_NAME;
	TableID.uName.pwszName	= m_pTable->GetTableName();

	// set a primary key constraint on the second column
	consPK.AddColumn(&rgColumnDesc[1].dbcid);
	consPK.AddColumn(&rgColumnDesc[3].dbcid);
	consPK.AddColumn(&rgColumnDesc[2].dbcid);

	TESTC_(CreateAndCheckTableWithConstraints(m_pITDWC, NULL, &TableID, cColumnDesc, rgColumnDesc, 
		1, consPK, 
		IID_IRowset, 0, NULL, NULL, NULL), S_OK);
	
CLEANUP:
	CHECK(DropTableAndCheck(&TableID), S_OK);
	ReleaseColumnDesc(rgColumnDesc, cColumnDesc);
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(6)
//*-----------------------------------------------------------------------
// @mfunc Table with a foreign key constraint (single column)
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCCreateTableWithConstraints::Variation_6()
{ 
	TBEGIN
	DBID				TableID;
	DBCOLUMNDESC		*rgColumnDesc	= NULL;
	DBORDINAL			cColumnDesc		= 0;
	DBORDINAL			indexCol		= 2;
	CTable				ReferencedTable(m_pThisTestModule->m_pIUnknown2, (LPWSTR)gwszModuleName);
	CForeignKeyCons		consFK(NULL, m_SupportedMatchType);
	CCol				col;


	DuplicateColumnDesc(m_rgColumnDesc, m_cColumnDesc, &rgColumnDesc);
	cColumnDesc = m_cColumnDesc;
	// release the properties on all column and make the first column not nullable
	ReleaseAllColumnPropSets(rgColumnDesc, cColumnDesc);
	SetProperty(&rgColumnDesc[0].rgPropertySets, &rgColumnDesc[0].cPropertySets,
			DBPROP_COL_NULLABLE, 
			VT_BOOL, (LPVOID)VARIANT_FALSE, 
			DBPROPOPTIONS_REQUIRED);

	m_pTable->MakeTableName(NULL);
	TableID.eKind			= DBKIND_NAME;
	TableID.uName.pwszName	= m_pTable->GetTableName();

	// create support for foreign key constraint
	TESTC_(ReferencedTable.CreateTable(0, 0), S_OK);
	ReferencedTable.AddInfoFromColumnsSchemaRowset(m_pITDWC, ReferencedTable.GetTableName());
	// make the referenced columns unique
	TESTC_(AddUniqueConstraint(&ReferencedTable, indexCol, (DBDEFERRABILITY)0), S_OK);

	// set a simple foreign key constraint
	TESTC_(ReferencedTable.GetColInfo(indexCol, col), S_OK);
	consFK.AddColumn(col.GetColID());
	consFK.AddForeignKeyColumn(&rgColumnDesc[indexCol-1].dbcid);
	consFK.SetReferencedTableID(&ReferencedTable.GetTableID());
	TESTC_(consFK.MakeConstraintName(), S_OK);

	TESTC_(CreateAndCheckTableWithConstraints(m_pITDWC, NULL, &TableID, cColumnDesc, rgColumnDesc, 
		1, consFK, 
		IID_IRowset, 0, NULL, NULL, NULL), S_OK);
	
CLEANUP:
	CHECK(DropTableAndCheck(&TableID), S_OK);
	CHECK(ReferencedTable.DropTable(), S_OK);
	ReleaseColumnDesc(rgColumnDesc, cColumnDesc);
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(7)
//*-----------------------------------------------------------------------
// @mfunc Table with foreign key constraint defined on multiple keys
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCCreateTableWithConstraints::Variation_7()
{ 
	TBEGIN
	DBID				TableID;
	DBCOLUMNDESC		*rgColumnDesc	= NULL;
	DBORDINAL			cColumnDesc		= 0;
	DBORDINAL			rgColumns[]		= {2, 1};
	CTable				ReferencedTable(m_pThisTestModule->m_pIUnknown2, (LPWSTR)gwszModuleName);
	CForeignKeyCons		consFK(NULL, m_SupportedMatchType);
	CCol				col;


	DuplicateColumnDesc(m_rgColumnDesc, m_cColumnDesc, &rgColumnDesc);
	cColumnDesc = m_cColumnDesc;

	m_pTable->MakeTableName(NULL);
	TableID.eKind			= DBKIND_NAME;
	TableID.uName.pwszName	= m_pTable->GetTableName();

	// create support for foreign key constraint
	TESTC_(ReferencedTable.CreateTable(0, 0), S_OK);
	ReferencedTable.AddInfoFromColumnsSchemaRowset(m_pITDWC, ReferencedTable.GetTableName());
	// make the referenced columns unique
	TESTC_(AddUniqueConstraint(&ReferencedTable, NUMELEM(rgColumns), rgColumns, (DBDEFERRABILITY)0), S_OK);

	// set a simple foreign key constraint
	TESTC_(ReferencedTable.GetColInfo(rgColumns[0], col), S_OK);
	consFK.AddColumn(col.GetColID());
	TESTC_(ReferencedTable.GetColInfo(rgColumns[1], col), S_OK);
	consFK.AddColumn(col.GetColID());

	consFK.AddForeignKeyColumn(&rgColumnDesc[rgColumns[0]-1].dbcid);
	consFK.AddForeignKeyColumn(&rgColumnDesc[rgColumns[1]-1].dbcid);

	consFK.SetReferencedTableID(&ReferencedTable.GetTableID());
	TESTC_(consFK.MakeConstraintName(), S_OK);

	TESTC_(CreateAndCheckTableWithConstraints(m_pITDWC, NULL, &TableID, cColumnDesc, rgColumnDesc, 
		1, consFK, 
		IID_IRowset, 0, NULL, NULL, NULL), S_OK);
	
CLEANUP:
	CHECK(DropTableAndCheck(&TableID), S_OK);
	CHECK(ReferencedTable.DropTable(), S_OK);
	ReleaseColumnDesc(rgColumnDesc, cColumnDesc);
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(8)
//*-----------------------------------------------------------------------
// @mfunc Table with a simple check constraint
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCCreateTableWithConstraints::Variation_8()
{ 
	TBEGIN
	DBID				TableID;
	DBCOLUMNDESC		*rgColumnDesc	= NULL;
	DBORDINAL			cColumnDesc		= 0;
	CCheckCons			cons;
	WCHAR				*pwszConstraintText	= NULL;
	WCHAR				wszText[] = L" IS NOT NULL";

	DuplicateColumnDesc(m_rgColumnDesc, m_cColumnDesc, &rgColumnDesc);
	cColumnDesc = m_cColumnDesc;

	m_pTable->MakeTableName(NULL);
	TableID.eKind			= DBKIND_NAME;
	TableID.uName.pwszName	= m_pTable->GetTableName();

	// build constraint text
	TESTC_PROVIDER(DBKIND_NAME == rgColumnDesc[0].dbcid.eKind);
	SAFE_ALLOC(pwszConstraintText, WCHAR, 1 + wcslen(rgColumnDesc[0].dbcid.uName.pwszName) + wcslen(wszText));
	wcscpy(pwszConstraintText, rgColumnDesc[0].dbcid.uName.pwszName);
	wcscat(pwszConstraintText, wszText);
	cons.SetConstraintText(pwszConstraintText);

	TESTC_(CreateAndCheckTableWithConstraints(m_pITDWC, NULL, &TableID, cColumnDesc, rgColumnDesc, 
		1, cons, 
		IID_IRowset, 0, NULL, NULL, NULL), S_OK);
	
CLEANUP:
	SAFE_FREE(pwszConstraintText);
	CHECK(DropTableAndCheck(&TableID), S_OK);
	ReleaseColumnDesc(rgColumnDesc, cColumnDesc);
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(9)
//*-----------------------------------------------------------------------
// @mfunc Table with multiple unique constraints defined
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCCreateTableWithConstraints::Variation_9()
{ 
	TBEGIN
	DBID			TableID;
	DBCOLUMNDESC	*rgColumnDesc	= NULL;
	DBORDINAL		cColumnDesc		= 0;
	CConsDescArray	ConsDescArray;
	CUniqueCons		consUnique;
	CUniqueCons		consUnique1;

	DuplicateColumnDesc(m_rgColumnDesc, m_cColumnDesc, &rgColumnDesc);
	cColumnDesc = m_cColumnDesc;

	m_pTable->MakeTableName(NULL);
	TableID.eKind			= DBKIND_NAME;
	TableID.uName.pwszName	= m_pTable->GetTableName();

	// set a unique constraint on the second column
	consUnique.AddColumn(&rgColumnDesc[1].dbcid);
	consUnique.MakeConstraintName();

	// set second unique constraints on the firstcolumn
	consUnique1.AddColumn(&rgColumnDesc[0].dbcid);
	consUnique1.MakeConstraintName();

	// add all constraint to the array
	ConsDescArray.AddConsDesc(consUnique);
	ConsDescArray.AddConsDesc(consUnique1);

	TESTC_(CreateAndCheckTableWithConstraints(m_pITDWC, NULL, &TableID, cColumnDesc, rgColumnDesc, 
		ConsDescArray, ConsDescArray, 
		IID_IRowset, 0, NULL, NULL, NULL), S_OK);
	
CLEANUP:
	CHECK(DropTableAndCheck(&TableID), S_OK);
	ReleaseColumnDesc(rgColumnDesc, cColumnDesc);
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(10)
//*-----------------------------------------------------------------------
// @mfunc Table with unique constraint and foreign key
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCCreateTableWithConstraints::Variation_10()
{ 
	TBEGIN
	CTable			ReferencedTable(m_pThisTestModule->m_pIUnknown2, (LPWSTR)gwszModuleName);
	DBID			TableID;
	DBCOLUMNDESC	*rgColumnDesc	= NULL;
	DBORDINAL		cColumnDesc		= 0;
	CConsDescArray	ConsDescArray;
	CUniqueCons		consUnique;
	CForeignKeyCons	consForeignKey(NULL, m_SupportedMatchType);
	DBORDINAL		rgReferencedCol[] = {1};
	CCol			col;


	DuplicateColumnDesc(m_rgColumnDesc, m_cColumnDesc, &rgColumnDesc);
	cColumnDesc = m_cColumnDesc;

	m_pTable->MakeTableName(NULL);
	TableID.eKind			= DBKIND_NAME;
	TableID.uName.pwszName	= m_pTable->GetTableName();

	// create support for foreign key constraint
	TESTC_(ReferencedTable.CreateTable(0, 0), S_OK);
	ReferencedTable.AddInfoFromColumnsSchemaRowset(m_pITDWC, ReferencedTable.GetTableName());
	// make the referenced columns unique
	TESTC_(AddUniqueConstraint(&ReferencedTable, rgReferencedCol[0], (DBDEFERRABILITY)0), S_OK);

	// set a unique constraint on the second column
	consUnique.AddColumn(&rgColumnDesc[1].dbcid);
	consUnique.MakeConstraintName();

	// set a simple foreign key constraint
	TESTC_(ReferencedTable.GetColInfo(1, col), S_OK);
	consForeignKey.AddColumn(col.GetColID());
	consForeignKey.AddForeignKeyColumn(&rgColumnDesc[0].dbcid);
	consForeignKey.SetReferencedTableID(&ReferencedTable.GetTableID());
	consForeignKey.MakeConstraintName();

	// add all constraint to the array
	ConsDescArray.AddConsDesc(consForeignKey);
	ConsDescArray.AddConsDesc(consUnique);

	TESTC_(CreateAndCheckTableWithConstraints(m_pITDWC, NULL, &TableID, cColumnDesc, rgColumnDesc, 
		ConsDescArray, ConsDescArray, 
		IID_IRowset, 0, NULL, NULL, NULL), S_OK);
	
CLEANUP:
	CHECK(DropTableAndCheck(&TableID), S_OK);
	CHECK(ReferencedTable.DropTable(), S_OK);
	ReleaseColumnDesc(rgColumnDesc, cColumnDesc);
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(11)
//*-----------------------------------------------------------------------
// @mfunc Table with primary key and check constraint
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCCreateTableWithConstraints::Variation_11()
{ 
	TBEGIN
	DBID			TableID;
	DBCOLUMNDESC	*rgColumnDesc	= NULL;
	DBORDINAL		cColumnDesc		= 0;
	CConsDescArray	ConsDescArray;
	CPrimaryKeyCons	consPK;
	CCheckCons		consCheck;
	WCHAR			*pwszConstraintText	= NULL;
	WCHAR			wszText[] = L" IS NOT NULL";


	DuplicateColumnDesc(m_rgColumnDesc, m_cColumnDesc, &rgColumnDesc);
	cColumnDesc = m_cColumnDesc;
	// release the properties on all column and make the first column not nullable
	ReleaseAllColumnPropSets(rgColumnDesc, cColumnDesc);
	SetProperty(&rgColumnDesc[0].rgPropertySets, &rgColumnDesc[0].cPropertySets,
			DBPROP_COL_NULLABLE, 
			VT_BOOL, (LPVOID)VARIANT_FALSE, 
			DBPROPOPTIONS_REQUIRED);
	SetProperty(&rgColumnDesc[1].rgPropertySets, &rgColumnDesc[1].cPropertySets,
			DBPROP_COL_NULLABLE, 
			VT_BOOL, (LPVOID)VARIANT_FALSE, 
			DBPROPOPTIONS_REQUIRED);

	m_pTable->MakeTableName(NULL);
	TableID.eKind			= DBKIND_NAME;
	TableID.uName.pwszName	= m_pTable->GetTableName();

	// set a primary key constraint on the first column
	consPK.AddColumn(&rgColumnDesc[0].dbcid);

	// build constraint text
	TESTC_PROVIDER(DBKIND_NAME == rgColumnDesc[1].dbcid.eKind);
	SAFE_ALLOC(pwszConstraintText, WCHAR, 1 + wcslen(rgColumnDesc[1].dbcid.uName.pwszName) + wcslen(wszText));
	wcscpy(pwszConstraintText, rgColumnDesc[1].dbcid.uName.pwszName);
	wcscat(pwszConstraintText, wszText);
	consCheck.SetConstraintText(pwszConstraintText);

	// add all constraint to the array
	ConsDescArray.AddConsDesc(consPK);
	ConsDescArray.AddConsDesc(consCheck);

	TESTC_(CreateAndCheckTableWithConstraints(m_pITDWC, NULL, &TableID, cColumnDesc, rgColumnDesc, 
		ConsDescArray, ConsDescArray, 
		IID_IRowset, 0, NULL, NULL, NULL), S_OK);
	
CLEANUP:
	SAFE_FREE(pwszConstraintText);
	CHECK(DropTableAndCheck(&TableID), S_OK);
	ReleaseColumnDesc(rgColumnDesc, cColumnDesc);
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(12)
//*-----------------------------------------------------------------------
// @mfunc Deferrable, immediate constraints
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCCreateTableWithConstraints::Variation_12()
{ 
	TBEGIN
	CTable			ReferencedTable(m_pThisTestModule->m_pIUnknown2, (LPWSTR)gwszModuleName);
	DBID			TableID;
	DBCOLUMNDESC	*rgColumnDesc	= NULL;
	DBORDINAL		cColumnDesc		= 0;
	CUniqueCons		consUnique;
	CPrimaryKeyCons	consPrimaryKey;
	CForeignKeyCons	consForeignKey(NULL, m_SupportedMatchType);
	CCheckCons		consCheck;
	WCHAR			*pwszConstraintText	= NULL;
	WCHAR			wszText[] = L" IS NULL";
	DBORDINAL		rgReferencedCol[] = {1};
	CCol			col;
	HRESULT			hr;

	DuplicateColumnDesc(m_rgColumnDesc, m_cColumnDesc, &rgColumnDesc);
	cColumnDesc = m_cColumnDesc;
	// release the properties on all column and make the first column not nullable
	ReleaseAllColumnPropSets(rgColumnDesc, cColumnDesc);
	SetProperty(&rgColumnDesc[0].rgPropertySets, &rgColumnDesc[0].cPropertySets,
			DBPROP_COL_NULLABLE, 
			VT_BOOL, (LPVOID)VARIANT_FALSE, 
			DBPROPOPTIONS_REQUIRED);

	m_pTable->MakeTableName(NULL);
	TableID.eKind			= DBKIND_NAME;
	TableID.uName.pwszName	= m_pTable->GetTableName();

	// create support for foreign key constraint
	TESTC_(ReferencedTable.CreateTable(0, 0), S_OK);
	ReferencedTable.AddInfoFromColumnsSchemaRowset(m_pITDWC, ReferencedTable.GetTableName());
	// make the referenced columns unique
	TESTC_(AddUniqueConstraint(&ReferencedTable, rgReferencedCol[0], (DBDEFERRABILITY)0), S_OK);

	// set a unique constraint on the second column
	consUnique.AddColumn(&rgColumnDesc[1].dbcid);
	consUnique.SetDeferrability(DBDEFERRABILITY_DEFERRABLE);

	// try to create a table with a deferrable unique constraint
	hr = CreateAndCheckTableWithConstraints(m_pITDWC, NULL, &TableID, cColumnDesc, rgColumnDesc, 
		1, consUnique, IID_IRowset, 0, NULL, NULL, NULL);

	if (S_OK == hr)
	{
		// drop the table
		CHECK(DropTableAndCheck(&TableID, m_pITableDefinition), S_OK);
	}
	else
	{
		CHECK(hr, DB_E_BADDEFERRABILITY);
	}

	// set a primary key on the first column of the table
	consPrimaryKey.AddColumn(&rgColumnDesc[0].dbcid);
	consPrimaryKey.SetDeferrability(DBDEFERRABILITY_DEFERRABLE);

	// try to create a table with a deferrable primary key constraint
	hr = CreateAndCheckTableWithConstraints(m_pITDWC, NULL, &TableID, cColumnDesc, rgColumnDesc, 
		1, consPrimaryKey, IID_IRowset, 0, NULL, NULL, NULL);

	if (S_OK == hr)
	{
		// drop the table
		CHECK(DropTableAndCheck(&TableID, m_pITableDefinition), S_OK);
	}
	else
	{
		CHECK(hr, DB_E_BADDEFERRABILITY);
	}

	// set a simple foreign key constraint
	TESTC_(ReferencedTable.GetColInfo(1, col), S_OK);
	consForeignKey.AddColumn(col.GetColID());
	consForeignKey.AddForeignKeyColumn(&rgColumnDesc[0].dbcid);
	consForeignKey.SetReferencedTableID(&ReferencedTable.GetTableID());
	consForeignKey.SetDeferrability(DBDEFERRABILITY_DEFERRABLE);

	// try to create a table with a deferrable foreign key constraint
	hr = CreateAndCheckTableWithConstraints(m_pITDWC, NULL, &TableID, cColumnDesc, rgColumnDesc, 
		1, consForeignKey, IID_IRowset, 0, NULL, NULL, NULL);

	if (S_OK == hr)
	{
		// drop the table
		CHECK(DropTableAndCheck(&TableID, m_pITableDefinition), S_OK);
	}
	else
	{
		CHECK(hr, DB_E_BADDEFERRABILITY);
	}

	// build constraint text
	TESTC_PROVIDER(DBKIND_NAME == rgColumnDesc[4].dbcid.eKind);
	SAFE_ALLOC(pwszConstraintText, WCHAR, 1 + wcslen(rgColumnDesc[4].dbcid.uName.pwszName) + wcslen(wszText));
	wcscpy(pwszConstraintText, rgColumnDesc[4].dbcid.uName.pwszName);
	wcscat(pwszConstraintText, wszText);
	consCheck.SetConstraintText(pwszConstraintText);
	consCheck.SetDeferrability(DBDEFERRABILITY_DEFERRABLE);

	// try to create a table with a deferrable check constraint
	hr = CreateAndCheckTableWithConstraints(m_pITDWC, NULL, &TableID, cColumnDesc, rgColumnDesc, 
		1, consCheck, IID_IRowset, 0, NULL, NULL, NULL);

	if (S_OK == hr)
	{
		// drop the table
		CHECK(DropTableAndCheck(&TableID, m_pITableDefinition), S_OK);
	}
	else
	{
		CHECK(hr, DB_E_BADDEFERRABILITY);
	}
	
	
CLEANUP:
	SAFE_FREE(pwszConstraintText);
	DropTableAndCheck(&TableID);
	CHECK(ReferencedTable.DropTable(), S_OK);
	ReleaseColumnDesc(rgColumnDesc, cColumnDesc);
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(13)
//*-----------------------------------------------------------------------
// @mfunc Deferred constraints
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCCreateTableWithConstraints::Variation_13()
{ 
	TBEGIN
	CTable			ReferencedTable(m_pThisTestModule->m_pIUnknown2, (LPWSTR)gwszModuleName);
	DBID			TableID;
	DBCOLUMNDESC	*rgColumnDesc	= NULL;
	DBORDINAL		cColumnDesc		= 0;
	CUniqueCons		consUnique;
	CPrimaryKeyCons	consPrimaryKey;
	CForeignKeyCons	consForeignKey(NULL, m_SupportedMatchType);
	CCheckCons		consCheck;
	WCHAR			*pwszConstraintText	= NULL;
	WCHAR			wszText[] = L" IS NULL";
	DBORDINAL		rgReferencedCol[] = {1};
	CCol			col;
	HRESULT			hr;
	CTable			Table(m_pITableDefinition, (LPWSTR)gwszModuleName);

	DuplicateColumnDesc(m_rgColumnDesc, m_cColumnDesc, &rgColumnDesc);
	cColumnDesc = m_cColumnDesc;
	// release the properties on all column and make the first column not nullable
	ReleaseAllColumnPropSets(rgColumnDesc, cColumnDesc);
	SetProperty(&rgColumnDesc[0].rgPropertySets, &rgColumnDesc[0].cPropertySets,
			DBPROP_COL_NULLABLE, 
			VT_BOOL, (LPVOID)VARIANT_FALSE, 
			DBPROPOPTIONS_REQUIRED);

	m_pTable->MakeTableName(NULL);
	TableID.eKind			= DBKIND_NAME;
	TableID.uName.pwszName	= m_pTable->GetTableName();

	// create support for foreign key constraint
	TESTC_(ReferencedTable.CreateTable(0, 0), S_OK);
	ReferencedTable.AddInfoFromColumnsSchemaRowset(m_pITDWC, ReferencedTable.GetTableName());
	// make the referenced columns unique
	TESTC_(AddUniqueConstraint(&ReferencedTable, rgReferencedCol[0], (DBDEFERRABILITY)0), S_OK);

	// set a unique constraint on the second column
	consUnique.AddColumn(&rgColumnDesc[1].dbcid);
	consUnique.SetDeferrability(DBDEFERRABILITY_DEFERRABLE | DBDEFERRABILITY_DEFERRED);

	// try to create a table with a deferrable unique constraint
	hr = CreateAndCheckTableWithConstraints(m_pITDWC, NULL, &TableID, cColumnDesc, rgColumnDesc, 
		1, consUnique, IID_IRowset, 0, NULL, NULL, NULL);

	if (S_OK == hr)
	{
		// try to insert a duplicate value in the second column and check it is possible
		Table.SetTableID(TableID);
		if (CHECK(Table.GetTableColumnInfo(&TableID), S_OK))
		{
			CHECK(Table.Insert(1), S_OK);
			CHECK(Table.Insert(1), S_OK);
		}
		// drop the table
		CHECK(DropTableAndCheck(&TableID, m_pITableDefinition), S_OK);
	}
	else
	{
		CHECK(hr, DB_E_BADDEFERRABILITY);
	}

	// set a primary key on the first column of the table
	consPrimaryKey.AddColumn(&rgColumnDesc[0].dbcid);
	consPrimaryKey.SetDeferrability(DBDEFERRABILITY_DEFERRABLE | DBDEFERRABILITY_DEFERRED);

	// try to create a table with a deferrable primary key constraint
	hr = CreateAndCheckTableWithConstraints(m_pITDWC, NULL, &TableID, cColumnDesc, rgColumnDesc, 
		1, consPrimaryKey, IID_IRowset, 0, NULL, NULL, NULL);

	if (S_OK == hr)
	{
		// try to insert a duplicate value in the primary key column and check it is possible
		Table.SetTableID(TableID);
		if (CHECK(Table.GetTableColumnInfo(&TableID), S_OK))
		{
			CHECK(Table.Insert(1), S_OK);
			CHECK(Table.Insert(1), S_OK);
		}
		// drop the table
		CHECK(DropTableAndCheck(&TableID, m_pITableDefinition), S_OK);
	}
	else
	{
		CHECK(hr, DB_E_BADDEFERRABILITY);
	}

	// set a simple foreign key constraint
	TESTC_(ReferencedTable.GetColInfo(1, col), S_OK);
	consForeignKey.AddColumn(col.GetColID());
	consForeignKey.AddForeignKeyColumn(&rgColumnDesc[0].dbcid);
	consForeignKey.SetReferencedTableID(&ReferencedTable.GetTableID());
	consForeignKey.SetDeferrability(DBDEFERRABILITY_DEFERRABLE | DBDEFERRABILITY_DEFERRED);

	// try to create a table with a deferrable foreign key constraint
	hr = CreateAndCheckTableWithConstraints(m_pITDWC, NULL, &TableID, cColumnDesc, rgColumnDesc, 
		1, consForeignKey, IID_IRowset, 0, NULL, NULL, NULL);

	if (S_OK == hr)
	{
		// try to insert a row base table (referenced table is empty)
		Table.SetTableID(TableID);
		if (CHECK(Table.GetTableColumnInfo(&TableID), S_OK))
		{
			CHECK(Table.Insert(7), S_OK);
			CHECK(Table.Insert(5), S_OK);
		}
		// drop the table
		CHECK(DropTableAndCheck(&TableID, m_pITableDefinition), S_OK);
	}
	else
	{
		CHECK(hr, DB_E_BADDEFERRABILITY);
	}

	// build constraint text
	TESTC_PROVIDER(DBKIND_NAME == rgColumnDesc[4].dbcid.eKind);
	SAFE_ALLOC(pwszConstraintText, WCHAR, 1 + wcslen(rgColumnDesc[4].dbcid.uName.pwszName) + wcslen(wszText));
	wcscpy(pwszConstraintText, rgColumnDesc[4].dbcid.uName.pwszName);
	wcscat(pwszConstraintText, wszText);
	consCheck.SetConstraintText(pwszConstraintText);
	consCheck.SetDeferrability(DBDEFERRABILITY_DEFERRABLE | DBDEFERRABILITY_DEFERRED);

	// try to create a table with a deferrable check constraint
	hr = CreateAndCheckTableWithConstraints(m_pITDWC, NULL, &TableID, cColumnDesc, rgColumnDesc, 
		1, consCheck, IID_IRowset, 0, NULL, NULL, NULL);

	if (S_OK == hr)
	{
		// try to insert a not null value in the checked column 
		Table.SetTableID(TableID);
		if (CHECK(Table.GetTableColumnInfo(&TableID), S_OK))
		{
			CHECK(Table.Insert(1), S_OK);
			CHECK(Table.Insert(10), S_OK);
		}
		// drop the table
		CHECK(DropTableAndCheck(&TableID, m_pITableDefinition), S_OK);
	}
	else
	{
		CHECK(hr, DB_E_BADDEFERRABILITY);
	}
	
	
CLEANUP:
	SAFE_FREE(pwszConstraintText);
	DropTableAndCheck(&TableID);
	CHECK(ReferencedTable.DropTable(), S_OK);
	ReleaseColumnDesc(rgColumnDesc, cColumnDesc);
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(14)
//*-----------------------------------------------------------------------
// @mfunc Abort retain
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCCreateTableWithConstraints::Variation_14()
{ 
	CCreateTableWithConsTxnAdapter	TxnAdapter(this);
	CTransactionLocal				TxnLocal;

	return TxnLocal.DoTransactionTest(m_pITDWC, &TxnAdapter,
		TRUE,		// DDL
		TRUE,		// Abort
		TRUE		// Retaining
		);
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(15)
//*-----------------------------------------------------------------------
// @mfunc Abort non retain
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCCreateTableWithConstraints::Variation_15()
{ 
	CCreateTableWithConsTxnAdapter	TxnAdapter(this);
	CTransactionLocal				TxnLocal;

	return TxnLocal.DoTransactionTest(m_pITDWC, &TxnAdapter,
		TRUE,		// DDL
		TRUE,		// Abort
		FALSE		// Non Retaining
		);
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(16)
//*-----------------------------------------------------------------------
// @mfunc Commit retain
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCCreateTableWithConstraints::Variation_16()
{ 
	CCreateTableWithConsTxnAdapter	TxnAdapter(this);
	CTransactionLocal				TxnLocal;

	return TxnLocal.DoTransactionTest(m_pITDWC, &TxnAdapter,
		TRUE,		// DDL
		FALSE,		// Commit
		TRUE		// Retaining
		);
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(17)
//*-----------------------------------------------------------------------
// @mfunc Commit non retain
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCCreateTableWithConstraints::Variation_17()
{ 
	CCreateTableWithConsTxnAdapter	TxnAdapter(this);
	CTransactionLocal				TxnLocal;

	return TxnLocal.DoTransactionTest(m_pITDWC, &TxnAdapter,
		TRUE,		// DDL
		FALSE,		// Commit
		FALSE		// Non Retaining
		);
} 
// }} TCW_VAR_PROTOTYPE_END


// {{ TCW_TERMINATE_METHOD
//*-----------------------------------------------------------------------
// @mfunc TestCase Termination Routine 
//
// @rdesc TEST_PASS or TEST_FAIL 
//
BOOL TCCreateTableWithConstraints::Terminate()
{ 
	// TO DO:  Add your own code here 

// {{ TCW_TERM_BASECLASS_CHECK2
	return(TCITableDefinition::Terminate());
} 	// }}
// }} TCW_TERMINATE_METHOD_END
// }} TCW_TC_PROTOTYPE_END


// {{ TCW_TC_PROTOTYPE(TCCreateTableWithConstraints_Boundary)
//*-----------------------------------------------------------------------
//| Test Case:		TCCreateTableWithConstraints_Boundary - Boundary and NULL testcase for ITableDefinitionWithConstraints::CreateTableWithConstraints
//| Created:  	9/3/99
//*-----------------------------------------------------------------------

//*-----------------------------------------------------------------------
// @mfunc TestCase Initialization Routine
//
// @rdesc TRUE or FALSE
//
BOOL TCCreateTableWithConstraints_Boundary::Init()
{ 
	// {{ TCW_INIT_BASECLASS_CHECK
	if(TCITableDefinition::Init())
	// }}
	{ 
		if (m_pITDWC == NULL)
		{
			odtLog << "ITableDefinitionWithConstraints is not supported.\n";
			return TEST_SKIPPED;
		}
		return TRUE;
	} 
	return FALSE;
} 




// {{ TCW_VAR_PROTOTYPE(1)
//*-----------------------------------------------------------------------
// @mfunc 0 < cConstraintDescs and NULL == rgConstraintDescs => E_INVALIDARG
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCCreateTableWithConstraints_Boundary::Variation_1()
{ 
	TBEGIN
	DBID			TableID;
	DBCOLUMNDESC	*rgColumnDesc	= NULL;
	DBORDINAL		cColumnDesc		= 0;

	DuplicateColumnDesc(m_rgColumnDesc, m_cColumnDesc, &rgColumnDesc);
	cColumnDesc = m_cColumnDesc;

	m_pTable->MakeTableName(NULL);
	TableID.eKind			= DBKIND_NAME;
	TableID.uName.pwszName	= m_pTable->GetTableName();

	TESTC_(CreateAndCheckTableWithConstraints(m_pITDWC, NULL, &TableID, cColumnDesc, rgColumnDesc, 
		3, NULL, 
		IID_IRowset, 0, NULL, NULL, NULL), E_INVALIDARG);
	
CLEANUP:
	ReleaseColumnDesc(rgColumnDesc, cColumnDesc);
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(2)
//*-----------------------------------------------------------------------
// @mfunc 0 == cConstraintDescs and NULL != rgConstraintDescs => S_OK
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCCreateTableWithConstraints_Boundary::Variation_2()
{ 
	TBEGIN
	DBID			TableID;
	DBCOLUMNDESC	*rgColumnDesc	= NULL;
	DBORDINAL		cColumnDesc		= 0;
	CUniqueCons		cons;

	DuplicateColumnDesc(m_rgColumnDesc, m_cColumnDesc, &rgColumnDesc);
	cColumnDesc = m_cColumnDesc;
	
	m_pTable->MakeTableName(NULL);
	TableID.eKind			= DBKIND_NAME;
	TableID.uName.pwszName	= m_pTable->GetTableName();

	cons.AddColumn(&rgColumnDesc[0].dbcid);
	
	TESTC_(CreateAndCheckTableWithConstraints(m_pITDWC, NULL, &TableID, cColumnDesc, rgColumnDesc, 
		0, cons, 
		IID_IRowset, 0, NULL, NULL, NULL), S_OK);
	
CLEANUP:
	CHECK(this->DropTableAndCheck(&TableID), S_OK);
	ReleaseColumnDesc(rgColumnDesc, cColumnDesc);
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END





// {{ TCW_VAR_PROTOTYPE(3)
//*-----------------------------------------------------------------------
// @mfunc pTableID is NULL ppTableID is not NULL => S_OK
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCCreateTableWithConstraints_Boundary::Variation_3()
{ 
	TBEGIN
	CTable			ReferencedTable(m_pITDWC, (LPWSTR)gwszModuleName);
	DBID			*pTableID		= NULL;
	DBCOLUMNDESC	*rgColumnDesc	= NULL;
	DBORDINAL		cColumnDesc		= 0;
	CConsDescArray	ConsDescArray;
	CUniqueCons		consUnique;
	CPrimaryKeyCons	consPrimaryKey;
	CForeignKeyCons	consForeignKey(NULL, m_SupportedMatchType);
	DBORDINAL		rgReferencedCol[] = {1};
	CCol			col;


	DuplicateColumnDesc(m_rgColumnDesc, m_cColumnDesc, &rgColumnDesc);
	cColumnDesc = m_cColumnDesc;
	ReleaseAllColumnPropSets(rgColumnDesc, cColumnDesc);
	SetProperty(&rgColumnDesc[0].rgPropertySets, &rgColumnDesc[0].cPropertySets,
			DBPROP_COL_NULLABLE, 
			VT_BOOL, (LPVOID)VARIANT_FALSE, 
			DBPROPOPTIONS_REQUIRED);

	// create support for foreign key constraint
	TESTC_(ReferencedTable.CreateTable(0, 0), S_OK);
	ReferencedTable.AddInfoFromColumnsSchemaRowset(m_pITDWC, ReferencedTable.GetTableName());
	// make the referenced columns unique
	TESTC_(AddUniqueConstraint(&ReferencedTable, rgReferencedCol[0], (DBDEFERRABILITY)0), S_OK);

	// set a unique constraint on the second column
	consUnique.AddColumn(&rgColumnDesc[1].dbcid);

	// set a primary key on the first column of the table
	consPrimaryKey.AddColumn(&rgColumnDesc[0].dbcid);

	// set a simple foreign key constraint
	TESTC_(ReferencedTable.GetColInfo(1, col), S_OK);
	consForeignKey.AddColumn(col.GetColID());
	consForeignKey.AddForeignKeyColumn(&rgColumnDesc[0].dbcid);
	consForeignKey.SetReferencedTableID(&ReferencedTable.GetTableID());

	// add all constraint to the array
	ConsDescArray.AddConsDesc(consUnique);
	ConsDescArray.AddConsDesc(consForeignKey);
	ConsDescArray.AddConsDesc(consPrimaryKey);
	
	TESTC_(CreateAndCheckTableWithConstraints(
		m_pITDWC, NULL, NULL, 
		cColumnDesc, rgColumnDesc, 
		ConsDescArray, ConsDescArray, 
		IID_IRowset, 0, NULL, 
		&pTableID, NULL), S_OK);
	
CLEANUP:
	CHECK(DropTableAndCheck(pTableID), S_OK);
	CHECK(ReferencedTable.DropTable(), S_OK);
	ReleaseColumnDesc(rgColumnDesc, cColumnDesc);
	ReleaseDBID(pTableID, TRUE);
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(4)
//*-----------------------------------------------------------------------
// @mfunc Bad DBKIND of a constraint ID
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCCreateTableWithConstraints_Boundary::Variation_4()
{ 
	TBEGIN
	CTable			ReferencedTable(m_pITDWC, (LPWSTR)gwszModuleName);
	DBID			*pTableID		= NULL;
	DBCOLUMNDESC	*rgColumnDesc	= NULL;
	DBORDINAL		cColumnDesc		= 0;
	CConsDescArray	ConsDescArray;
	CUniqueCons		consUnique;
	CPrimaryKeyCons	consPrimaryKey;
	CForeignKeyCons	consForeignKey(NULL, m_SupportedMatchType);
	DBORDINAL		rgReferencedCol[] = {1};
	CCol			col;

	DuplicateColumnDesc(m_rgColumnDesc, m_cColumnDesc, &rgColumnDesc);
	cColumnDesc = m_cColumnDesc;
	ReleaseAllColumnPropSets(rgColumnDesc, cColumnDesc);
	SetProperty(&rgColumnDesc[0].rgPropertySets, &rgColumnDesc[0].cPropertySets,
			DBPROP_COL_NULLABLE, 
			VT_BOOL, (LPVOID)VARIANT_FALSE, 
			DBPROPOPTIONS_REQUIRED);

	// create support for foreign key constraint
	TESTC_(ReferencedTable.CreateTable(0, 0), S_OK);
	ReferencedTable.AddInfoFromColumnsSchemaRowset(m_pITDWC, ReferencedTable.GetTableName());
	// make the referenced columns unique
	TESTC_(AddUniqueConstraint(&ReferencedTable, rgReferencedCol[0], (DBDEFERRABILITY)0), S_OK);

	// set a unique constraint on the second column
	consUnique.AddColumn(&rgColumnDesc[1].dbcid);

	// set a primary key on the first column of the table
	consPrimaryKey.AddColumn(&rgColumnDesc[0].dbcid);
	ReleaseDBID(((DBCONSTRAINTDESC*)consPrimaryKey)->pConstraintID, FALSE);
	((DBCONSTRAINTDESC*)consPrimaryKey)->pConstraintID->eKind = 0xb2;

	// set a simple foreign key constraint
	TESTC_(ReferencedTable.GetColInfo(1, col), S_OK);
	consForeignKey.AddColumn(col.GetColID());
	consForeignKey.AddForeignKeyColumn(&rgColumnDesc[0].dbcid);
	consForeignKey.SetReferencedTableID(&ReferencedTable.GetTableID());

	// add all constraint to the array
	ConsDescArray.AddConsDesc(consUnique);
	ConsDescArray.AddConsDesc(consForeignKey);
	ConsDescArray.AddConsDesc(consPrimaryKey);
	
	TESTC_(CreateAndCheckTableWithConstraints(
		m_pITDWC, NULL, NULL, 
		cColumnDesc, rgColumnDesc, 
		ConsDescArray, ConsDescArray, 
		IID_IRowset, 0, NULL, 
		&pTableID, NULL), DB_E_BADCONSTRAINTID);
	
CLEANUP:
	CHECK(ReferencedTable.DropTable(), S_OK);
	ReleaseColumnDesc(rgColumnDesc, cColumnDesc);
	ReleaseDBID(pTableID, TRUE);
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(5)
//*-----------------------------------------------------------------------
// @mfunc NULL pConstraintID in a constraint
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCCreateTableWithConstraints_Boundary::Variation_5()
{ 
	TBEGIN
	CTable			ReferencedTable(m_pITDWC, (LPWSTR)gwszModuleName);
	DBID			*pTableID		= NULL;
	DBCOLUMNDESC	*rgColumnDesc	= NULL;
	DBORDINAL		cColumnDesc		= 0;
	CConsDescArray	ConsDescArray;
	CUniqueCons		consUnique;
	CPrimaryKeyCons	consPrimaryKey;
	CForeignKeyCons	consForeignKey(NULL, m_SupportedMatchType);
	DBORDINAL		rgReferencedCol[] = {1};
	CCol			col;


	DuplicateColumnDesc(m_rgColumnDesc, m_cColumnDesc, &rgColumnDesc);
	cColumnDesc = m_cColumnDesc;
	ReleaseAllColumnPropSets(rgColumnDesc, cColumnDesc);
	SetProperty(&rgColumnDesc[0].rgPropertySets, &rgColumnDesc[0].cPropertySets,
			DBPROP_COL_NULLABLE, 
			VT_BOOL, (LPVOID)VARIANT_FALSE, 
			DBPROPOPTIONS_REQUIRED);

	// create support for foreign key constraint
	TESTC_(ReferencedTable.CreateTable(0, 0), S_OK);
	ReferencedTable.AddInfoFromColumnsSchemaRowset(m_pITDWC, ReferencedTable.GetTableName());
	// make the referenced columns unique
	TESTC_(AddUniqueConstraint(&ReferencedTable, rgReferencedCol[0], (DBDEFERRABILITY)0), S_OK);

	// set a unique constraint on the second column
	consUnique.AddColumn(&rgColumnDesc[1].dbcid);

	// set a primary key on the first column of the table
	consPrimaryKey.AddColumn(&rgColumnDesc[0].dbcid);
	ReleaseDBID(((DBCONSTRAINTDESC*)consPrimaryKey)->pConstraintID, TRUE);
	((DBCONSTRAINTDESC*)consPrimaryKey)->pConstraintID = NULL;

	// set a simple foreign key constraint
	TESTC_(ReferencedTable.GetColInfo(1, col), S_OK);
	consForeignKey.AddColumn(col.GetColID());
	consForeignKey.AddForeignKeyColumn(&rgColumnDesc[0].dbcid);
	consForeignKey.SetReferencedTableID(&ReferencedTable.GetTableID());

	// add all constraint to the array
	ConsDescArray.AddConsDesc(consUnique);
	ConsDescArray.AddConsDesc(consForeignKey);
	ConsDescArray.AddConsDesc(consPrimaryKey);
	
	TESTC_(CreateAndCheckTableWithConstraints(
		m_pITDWC, NULL, NULL, 
		cColumnDesc, rgColumnDesc, 
		ConsDescArray, ConsDescArray, 
		IID_IRowset, 0, NULL, 
		&pTableID, NULL), S_OK);
	
CLEANUP:
	CHECK(DropTableAndCheck(pTableID), S_OK);
	CHECK(ReferencedTable.DropTable(), S_OK);
	ReleaseColumnDesc(rgColumnDesc, cColumnDesc);
	ReleaseDBID(pTableID, TRUE);
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(6)
//*-----------------------------------------------------------------------
// @mfunc NULL column list in a constraint, column size is not 0 => E_INVALIDARG
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCCreateTableWithConstraints_Boundary::Variation_6()
{ 
	// this tests rgColumnList for PK, FK and unique constraints
	// as well as rgForeignKeyColumnList for FK
	TBEGIN
	CTable				ReferencedTable(m_pITDWC, (LPWSTR)gwszModuleName);
	DBID				*pTableID		= NULL;
	DBCOLUMNDESC		*rgColumnDesc	= NULL;
	DBORDINAL			cColumnDesc		= 0;
	CConsDescArray		ConsDescArray;
	CUniqueCons			consUnique;
	CUniqueCons			cons;
	CPrimaryKeyCons		consPrimaryKey;
	CForeignKeyCons		consForeignKey(NULL, m_SupportedMatchType);
	DBORDINAL			rgReferencedCol[] = {1};
	CCol				col;
	DBCONSTRAINTDESC	*pConsDesc;

	DuplicateColumnDesc(m_rgColumnDesc, m_cColumnDesc, &rgColumnDesc);
	cColumnDesc = m_cColumnDesc;
	ReleaseAllColumnPropSets(rgColumnDesc, cColumnDesc);
	SetProperty(&rgColumnDesc[0].rgPropertySets, &rgColumnDesc[0].cPropertySets,
			DBPROP_COL_NULLABLE, 
			VT_BOOL, (LPVOID)VARIANT_FALSE, 
			DBPROPOPTIONS_REQUIRED);

	// create support for foreign key constraint
	TESTC_(ReferencedTable.CreateTable(0, 0), S_OK);
	ReferencedTable.AddInfoFromColumnsSchemaRowset(m_pITDWC, ReferencedTable.GetTableName());
	// make the referenced columns unique
	TESTC_(AddUniqueConstraint(&ReferencedTable, rgReferencedCol[0], (DBDEFERRABILITY)0), S_OK);

	// set a unique constraint on the second column
	cons.AddColumn(&rgColumnDesc[0].dbcid);
	pConsDesc = consUnique;
	pConsDesc->cColumns		= 2;
	pConsDesc->rgColumnList	= NULL;
	ConsDescArray.AddConsDesc(cons);
	ConsDescArray.AddConsDesc(consUnique);
	TESTC_(CreateAndCheckTableWithConstraints(
		m_pITDWC, NULL, NULL, 
		cColumnDesc, rgColumnDesc, 
		ConsDescArray, ConsDescArray, 
		IID_IRowset, 0, NULL, 
		&pTableID, NULL), E_INVALIDARG);


	// set a primary key on the first column of the table
	pConsDesc = consPrimaryKey;
	pConsDesc->cColumns		= 5;
	pConsDesc->rgColumnList	= NULL;
	TESTC_(CreateAndCheckTableWithConstraints(
		m_pITDWC, NULL, NULL, 
		cColumnDesc, rgColumnDesc, 
		1, consPrimaryKey, 
		IID_IRowset, 0, NULL, 
		&pTableID, NULL), E_INVALIDARG);

	// set a simple foreign key constraint
	TESTC_(ReferencedTable.GetColInfo(1, col), S_OK);
	consForeignKey.AddForeignKeyColumn(&rgColumnDesc[0].dbcid);
	consForeignKey.SetReferencedTableID(&ReferencedTable.GetTableID());
	pConsDesc = consForeignKey;
	pConsDesc->cColumns		= 1;
	pConsDesc->rgColumnList	= NULL;
	TESTC_(CreateAndCheckTableWithConstraints(
		m_pITDWC, NULL, NULL, 
		cColumnDesc, rgColumnDesc, 
		1, consForeignKey, 
		IID_IRowset, 0, NULL, 
		&pTableID, NULL), E_INVALIDARG);

	// the same check for foreign key column list
	consForeignKey.ReleaseForeignKeyColumnList();
	pConsDesc->cForeignKeyColumns = 1;
	pConsDesc->cColumns = 0;
	consForeignKey.AddColumn(&rgColumnDesc[0].dbcid);
	TESTC_(CreateAndCheckTableWithConstraints(
		m_pITDWC, NULL, NULL, 
		cColumnDesc, rgColumnDesc, 
		1, consForeignKey, 
		IID_IRowset, 0, NULL, 
		&pTableID, NULL), E_INVALIDARG);
	
CLEANUP:
	CHECK(ReferencedTable.DropTable(), S_OK);
	ReleaseColumnDesc(rgColumnDesc, cColumnDesc);
	ReleaseDBID(pTableID, TRUE);
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(7)
//*-----------------------------------------------------------------------
// @mfunc Empty list of columns for a unique, primay key or foreign key constraint
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCCreateTableWithConstraints_Boundary::Variation_7()
{ 
	// this tests rgColumnList for PK, FK and unique constraints
	// as well as rgForeignKeyColumnList for FK
	TBEGIN
	CTable				ReferencedTable(m_pITDWC, (LPWSTR)gwszModuleName);
	DBID				*pTableID		= NULL;
	DBCOLUMNDESC		*rgColumnDesc	= NULL;
	DBORDINAL			cColumnDesc		= 0;
	CConsDescArray		ConsDescArray;
	CUniqueCons			consUnique;
	CUniqueCons			cons;
	CPrimaryKeyCons		consPrimaryKey;
	CForeignKeyCons		consForeignKey(NULL, m_SupportedMatchType);
	DBORDINAL			rgReferencedCol[] = {1};
	CCol				col;

	DuplicateColumnDesc(m_rgColumnDesc, m_cColumnDesc, &rgColumnDesc);
	cColumnDesc = m_cColumnDesc;
	ReleaseAllColumnPropSets(rgColumnDesc, cColumnDesc);
	SetProperty(&rgColumnDesc[0].rgPropertySets, &rgColumnDesc[0].cPropertySets,
			DBPROP_COL_NULLABLE, 
			VT_BOOL, (LPVOID)VARIANT_FALSE, 
			DBPROPOPTIONS_REQUIRED);

	// create support for foreign key constraint
	TESTC_(ReferencedTable.CreateTable(0, 0), S_OK);
	ReferencedTable.AddInfoFromColumnsSchemaRowset(m_pITDWC, ReferencedTable.GetTableName());
	// make the referenced columns unique
	TESTC_(AddUniqueConstraint(&ReferencedTable, rgReferencedCol[0], (DBDEFERRABILITY)0), S_OK);

	// set a unique constraint on the second column
	cons.AddColumn(&rgColumnDesc[0].dbcid);
	ConsDescArray.AddConsDesc(cons);
	ConsDescArray.AddConsDesc(consUnique);
	TESTC_(CreateAndCheckTableWithConstraints(
		m_pITDWC, NULL, NULL, 
		cColumnDesc, rgColumnDesc, 
		ConsDescArray, ConsDescArray, 
		IID_IRowset, 0, NULL, 
		&pTableID, NULL), DB_E_BADCONSTRAINTFORM);


	// set a primary key on the first column of the table
	TESTC_(CreateAndCheckTableWithConstraints(
		m_pITDWC, NULL, NULL, 
		cColumnDesc, rgColumnDesc, 
		1, consPrimaryKey, 
		IID_IRowset, 0, NULL, 
		&pTableID, NULL), DB_E_BADCONSTRAINTFORM);

	// set a simple foreign key constraint
	TESTC_(ReferencedTable.GetColInfo(1, col), S_OK);
	consForeignKey.AddForeignKeyColumn(&rgColumnDesc[0].dbcid);
	consForeignKey.SetReferencedTableID(&ReferencedTable.GetTableID());
	TEST2C_(CreateAndCheckTableWithConstraints(
		m_pITDWC, NULL, NULL, 
		cColumnDesc, rgColumnDesc, 
		1, consForeignKey, 
		IID_IRowset, 0, NULL, 
		&pTableID, NULL), E_INVALIDARG, DB_E_BADCONSTRAINTFORM);

	// the same check for foreign key column list
	consForeignKey.ReleaseForeignKeyColumnList();
	consForeignKey.AddColumn(&rgColumnDesc[0].dbcid);
	TESTC_(CreateAndCheckTableWithConstraints(
		m_pITDWC, NULL, NULL, 
		cColumnDesc, rgColumnDesc, 
		1, consForeignKey, 
		IID_IRowset, 0, NULL, 
		&pTableID, NULL), DB_E_BADCONSTRAINTFORM);
	
CLEANUP:
	CHECK(ReferencedTable.DropTable(), S_OK);
	ReleaseColumnDesc(rgColumnDesc, cColumnDesc);
	ReleaseDBID(pTableID, TRUE);
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(8)
//*-----------------------------------------------------------------------
// @mfunc Non empty list of columns for a check constraint
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCCreateTableWithConstraints_Boundary::Variation_8()
{
	// this tests the case when rgColumnList or rgForeignKeyColumnList 
	// are not empty in a check constraint
	TBEGIN
	CCheckCons			consCheck;
	DBCONSTRAINTDESC	*pcons = consCheck;
	WCHAR				*pwszConstraintText	= NULL;
	DBCOLUMNDESC		*rgColumnDesc	= NULL;
	DBORDINAL			cColumnDesc		= 0;
	DBID				*pTableID		= NULL;
	WCHAR				wszText[]		= L" IS NOT NULL";

	DuplicateColumnDesc(m_rgColumnDesc, m_cColumnDesc, &rgColumnDesc);
	cColumnDesc = m_cColumnDesc;
	TESTC_PROVIDER(DBKIND_NAME == rgColumnDesc[0].dbcid.eKind
		&& rgColumnDesc[0].dbcid.uName.pwszName);

	// set up the check constraint
	// create the text of the constraint
	SAFE_FREE(pwszConstraintText);
	SAFE_ALLOC(pwszConstraintText, WCHAR, 1 + wcslen(rgColumnDesc[0].dbcid.uName.pwszName) + wcslen(wszText));
	wcscpy(pwszConstraintText, rgColumnDesc[0].dbcid.uName.pwszName);
	wcscat(pwszConstraintText, wszText);
	consCheck.SetConstraintText(pwszConstraintText);

	// not empty rgColumnList
	pcons->cColumns = 1;
	pcons->rgColumnList = &rgColumnDesc[0].dbcid;
	TESTC_(CreateAndCheckTableWithConstraints(
		m_pITDWC, NULL, NULL, 
		cColumnDesc, rgColumnDesc, 
		1, consCheck, 
		IID_IRowset, 0, NULL, 
		&pTableID, NULL), DB_E_BADCONSTRAINTFORM);

	// not empty rgForeignKeyColumnList
	pcons->cColumns = 0;
	pcons->rgColumnList = NULL;
	pcons->cForeignKeyColumns = 1;
	pcons->rgForeignKeyColumnList = &rgColumnDesc[0].dbcid;
	TEST2C_(CreateAndCheckTableWithConstraints(
		m_pITDWC, NULL, NULL, 
		cColumnDesc, rgColumnDesc, 
		1, consCheck, 
		IID_IRowset, 0, NULL, 
		&pTableID, NULL), DB_E_BADCONSTRAINTFORM, E_INVALIDARG);

	// not empty rgColumnList and rgForeignKeyColumnList
	pcons->cColumns = 1;
	pcons->rgColumnList = &rgColumnDesc[0].dbcid;
	pcons->cForeignKeyColumns = 1;
	pcons->rgForeignKeyColumnList = &rgColumnDesc[0].dbcid;
	TESTC_(CreateAndCheckTableWithConstraints(
		m_pITDWC, NULL, NULL, 
		cColumnDesc, rgColumnDesc, 
		1, consCheck, 
		IID_IRowset, 0, NULL, 
		&pTableID, NULL), DB_E_BADCONSTRAINTFORM);

CLEANUP:
	pcons->cColumns = 0;
	pcons->rgColumnList = NULL;
	pcons->cForeignKeyColumns = 0;
	pcons->rgForeignKeyColumnList = NULL;
	SAFE_FREE(pwszConstraintText);
	ReleaseColumnDesc(rgColumnDesc, cColumnDesc);
	ReleaseDBID(pTableID, TRUE);
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(9)
//*-----------------------------------------------------------------------
// @mfunc Non empty list of foreign keys for a constraint that is not foreign key
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCCreateTableWithConstraints_Boundary::Variation_9()
{ 
	TBEGIN
	CForeignKeyCons		consFK;
	CUniqueCons			consUnique;
	CPrimaryKeyCons		consPK;
	CCheckCons			consCheck;
	const DBORDINAL		cColumns		= 2;
	DBID				rgColumnList[cColumns];
	DBCOLUMNDESC		*rgColumnDesc	= NULL;
	DBORDINAL			cColumnDesc		= 0;
	DBID				*pTableID		= NULL;

	DuplicateColumnDesc(m_rgColumnDesc, m_cColumnDesc, &rgColumnDesc);
	cColumnDesc = m_cColumnDesc;
	TESTC_PROVIDER(DBKIND_NAME == rgColumnDesc[0].dbcid.eKind
		&& rgColumnDesc[0].dbcid.uName.pwszName);

	rgColumnList[0].eKind				= DBKIND_NAME;
	rgColumnList[0].uName.pwszName	= (LPWSTR)0x01234567;
	rgColumnList[1].eKind				= 0xfe;
	rgColumnList[1].uName.pwszName	= (LPWSTR)0x01234567;
	
	// set up the unique constraint
	consUnique.AddColumn(&rgColumnDesc[0].dbcid);
	consUnique.AddColumn(&rgColumnDesc[1].dbcid);
	((DBCONSTRAINTDESC*)consUnique)->cForeignKeyColumns = cColumns;
	((DBCONSTRAINTDESC*)consUnique)->rgForeignKeyColumnList = rgColumnList;
	CHECK(CreateAndCheckTableWithConstraints(
		m_pITDWC, NULL, NULL, 
		cColumnDesc, rgColumnDesc, 
		1, consUnique, 
		IID_IRowset, 0, NULL, 
		&pTableID, NULL), DB_E_BADCONSTRAINTFORM);
	((DBCONSTRAINTDESC*)consUnique)->cForeignKeyColumns = 0;
	((DBCONSTRAINTDESC*)consUnique)->rgForeignKeyColumnList = NULL;

	// set up the primary key constraint
	consPK.AddColumn(&rgColumnDesc[0].dbcid);
	consPK.AddColumn(&rgColumnDesc[1].dbcid);
	((DBCONSTRAINTDESC*)consPK)->cForeignKeyColumns = cColumns;
	((DBCONSTRAINTDESC*)consPK)->rgForeignKeyColumnList = rgColumnList;
	CHECK(CreateAndCheckTableWithConstraints(
		m_pITDWC, NULL, NULL, 
		cColumnDesc, rgColumnDesc, 
		1, consPK, 
		IID_IRowset, 0, NULL, 
		&pTableID, NULL), DB_E_BADCONSTRAINTFORM);
	((DBCONSTRAINTDESC*)consPK)->cForeignKeyColumns = 0;
	((DBCONSTRAINTDESC*)consPK)->rgForeignKeyColumnList = NULL;

	// set up the check constraint
	consCheck.SetConstraintText(L"TRUE != FALSE");
	((DBCONSTRAINTDESC*)consCheck)->cForeignKeyColumns = cColumns;
	((DBCONSTRAINTDESC*)consCheck)->rgForeignKeyColumnList = rgColumnList;
	TEST2C_(CreateAndCheckTableWithConstraints(
		m_pITDWC, NULL, NULL, 
		cColumnDesc, rgColumnDesc, 
		1, consCheck, 
		IID_IRowset, 0, NULL, 
		&pTableID, NULL), E_INVALIDARG, DB_E_BADCONSTRAINTFORM);

CLEANUP:
	((DBCONSTRAINTDESC*)consCheck)->cForeignKeyColumns = 0;
	((DBCONSTRAINTDESC*)consCheck)->rgForeignKeyColumnList = NULL;
	ReleaseColumnDesc(rgColumnDesc, cColumnDesc);
	ReleaseDBID(pTableID, TRUE);
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(10)
//*-----------------------------------------------------------------------
// @mfunc 0 < cForeignKeyColumns and NULL == rgForeignKeyColumnList => E_INVALIDARG
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCCreateTableWithConstraints_Boundary::Variation_10()
{ 
	// this tests rgColumnList for PK, FK and unique constraints
	// as well as rgForeignKeyColumnList for FK
	TBEGIN
	CTable				ReferencedTable(m_pITDWC, (LPWSTR)gwszModuleName);
	DBID				*pTableID		= NULL;
	DBCOLUMNDESC		*rgColumnDesc	= NULL;
	DBORDINAL			cColumnDesc		= 0;
	CUniqueCons			cons;
	CForeignKeyCons		consForeignKey(NULL, m_SupportedMatchType);
	DBORDINAL			rgReferencedCol[] = {1};

	DuplicateColumnDesc(m_rgColumnDesc, m_cColumnDesc, &rgColumnDesc);
	cColumnDesc = m_cColumnDesc;

	// create support for foreign key constraint
	TESTC_(ReferencedTable.CreateTable(0, 0), S_OK);
	ReferencedTable.AddInfoFromColumnsSchemaRowset(m_pITDWC, ReferencedTable.GetTableName());
	// make the referenced columns unique
	TESTC_(AddUniqueConstraint(&ReferencedTable, rgReferencedCol[0], (DBDEFERRABILITY)0), S_OK);

	// set a simple foreign key constraint
	consForeignKey.AddForeignKeyColumn(&rgColumnDesc[0].dbcid);
	consForeignKey.AddColumn(&rgColumnDesc[0].dbcid);
	consForeignKey.SetReferencedTableID(&ReferencedTable.GetTableID());
	consForeignKey.ReleaseForeignKeyColumnList();
	((DBCONSTRAINTDESC*)consForeignKey)->cForeignKeyColumns = 1;
	consForeignKey.AddColumn(&rgColumnDesc[0].dbcid);
	TESTC_(CreateAndCheckTableWithConstraints(
		m_pITDWC, NULL, NULL, 
		cColumnDesc, rgColumnDesc, 
		1, consForeignKey, 
		IID_IRowset, 0, NULL, 
		&pTableID, NULL), E_INVALIDARG);
	
CLEANUP:
	CHECK(ReferencedTable.DropTable(), S_OK);
	ReleaseColumnDesc(rgColumnDesc, cColumnDesc);
	ReleaseDBID(pTableID, TRUE);
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(11)
//*-----------------------------------------------------------------------
// @mfunc Constraint is not foreign key and pReferencedTableID is not NULL
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCCreateTableWithConstraints_Boundary::Variation_11()
{ 
	TBEGIN
	CTable				ReferencedTable(m_pITDWC, (LPWSTR)gwszModuleName);
	CUniqueCons			consUnique;
	CPrimaryKeyCons		consPK;
	CCheckCons			consCheck;
	DBCOLUMNDESC		*rgColumnDesc	= NULL;
	DBORDINAL			cColumnDesc		= 0;
	DBID				*pTableID		= NULL;

	// create support for foreign key constraint
	TESTC_(ReferencedTable.CreateTable(0, 0), S_OK);
	ReferencedTable.AddInfoFromColumnsSchemaRowset(m_pITDWC, ReferencedTable.GetTableName());

	DuplicateColumnDesc(m_rgColumnDesc, m_cColumnDesc, &rgColumnDesc);
	cColumnDesc = m_cColumnDesc;
	TESTC_PROVIDER(DBKIND_NAME == rgColumnDesc[0].dbcid.eKind
		&& rgColumnDesc[0].dbcid.uName.pwszName);

	// set up the unique constraint
	consUnique.AddColumn(&rgColumnDesc[0].dbcid);
	consUnique.AddColumn(&rgColumnDesc[1].dbcid);


	DBID* pTempDBID = NULL;

	DuplicateDBID(ReferencedTable.GetTableIDRef(), pTempDBID);
	((DBCONSTRAINTDESC*)consUnique)->pReferencedTableID = pTempDBID;
	CHECK(CreateAndCheckTableWithConstraints(
		m_pITDWC, NULL, NULL, 
		cColumnDesc, rgColumnDesc, 
		1, consUnique, 
		IID_IRowset, 0, NULL, 
		&pTableID, NULL), DB_E_BADCONSTRAINTFORM);
	((DBCONSTRAINTDESC*)consUnique)->pReferencedTableID = NULL;

	// set up the primary key constraint
	consPK.AddColumn(&rgColumnDesc[0].dbcid);
	consPK.AddColumn(&rgColumnDesc[1].dbcid);
	DuplicateDBID(ReferencedTable.GetTableIDRef(), pTempDBID);
	((DBCONSTRAINTDESC*)consPK)->pReferencedTableID = pTempDBID;
	CHECK(CreateAndCheckTableWithConstraints(
		m_pITDWC, NULL, NULL, 
		cColumnDesc, rgColumnDesc, 
		1, consPK, 
		IID_IRowset, 0, NULL, 
		&pTableID, NULL), DB_E_BADCONSTRAINTFORM);
	((DBCONSTRAINTDESC*)consPK)->pReferencedTableID = NULL;

	// set up the check constraint
	consCheck.SetConstraintText(L"TRUE != FALSE");
	DuplicateDBID(ReferencedTable.GetTableIDRef(), pTempDBID);
	((DBCONSTRAINTDESC*)consCheck)->pReferencedTableID = pTempDBID;
	CHECK(CreateAndCheckTableWithConstraints(
		m_pITDWC, NULL, NULL, 
		cColumnDesc, rgColumnDesc, 
		1, consCheck, 
		IID_IRowset, 0, NULL, 
		&pTableID, NULL), DB_E_BADCONSTRAINTFORM);
	((DBCONSTRAINTDESC*)consCheck)->pReferencedTableID = NULL;

CLEANUP:
	CHECK(ReferencedTable.DropTable(), S_OK);
	ReleaseColumnDesc(rgColumnDesc, cColumnDesc);
	ReleaseDBID(pTableID, TRUE);
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(12)
//*-----------------------------------------------------------------------
// @mfunc NULL pReferencedTableID for a foreign key constraint (with and without cForeignKeyColumns being 0)
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCCreateTableWithConstraints_Boundary::Variation_12()
{ 
	TBEGIN
	CTable				ReferencedTable(m_pITDWC, (LPWSTR)gwszModuleName);
	CForeignKeyCons		consForeignKey(NULL, m_SupportedMatchType);
	DBCOLUMNDESC		*rgColumnDesc	= NULL;
	DBORDINAL			cColumnDesc		= 0;
	DBID				*pTableID		= NULL;
	CCol				col;

	// create support for foreign key constraint
	TESTC_(ReferencedTable.CreateTable(0, 0), S_OK);
	ReferencedTable.AddInfoFromColumnsSchemaRowset(m_pITDWC, ReferencedTable.GetTableName());

	DuplicateColumnDesc(m_rgColumnDesc, m_cColumnDesc, &rgColumnDesc);
	cColumnDesc = m_cColumnDesc;
	TESTC_PROVIDER(DBKIND_NAME == rgColumnDesc[0].dbcid.eKind
		&& rgColumnDesc[0].dbcid.uName.pwszName);

	// set up the check constraint
	consForeignKey.SetReferencedTableID(NULL);

	TESTC_(ReferencedTable.GetColInfo(1, col), S_OK);
	consForeignKey.AddColumn(col.GetColID());
	CHECK(CreateAndCheckTableWithConstraints(
		m_pITDWC, NULL, NULL, 
		cColumnDesc, rgColumnDesc, 
		1, consForeignKey, 
		IID_IRowset, 0, NULL, 
		&pTableID, NULL), DB_E_BADCONSTRAINTFORM);

	consForeignKey.AddForeignKeyColumn(&rgColumnDesc[0].dbcid);
	CHECK(consForeignKey.MakeConstraintName(), S_OK);
	CHECK(CreateAndCheckTableWithConstraints(
		m_pITDWC, NULL, NULL, 
		cColumnDesc, rgColumnDesc, 
		1, consForeignKey, 
		IID_IRowset, 0, NULL, 
		&pTableID, NULL), DB_E_BADCONSTRAINTFORM);

CLEANUP:
	CHECK(ReferencedTable.DropTable(), S_OK);
	ReleaseColumnDesc(rgColumnDesc, cColumnDesc);
	ReleaseDBID(pTableID, TRUE);
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(13)
//*-----------------------------------------------------------------------
// @mfunc NULL referenced table name for a foreign key constraint
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCCreateTableWithConstraints_Boundary::Variation_13()
{ 
	TBEGIN
	CTable				ReferencedTable(m_pITDWC, (LPWSTR)gwszModuleName);
	CForeignKeyCons		consForeignKey(NULL, m_SupportedMatchType);
	DBCOLUMNDESC		*rgColumnDesc	= NULL;
	DBORDINAL			cColumnDesc		= 0;
	DBID				*pTableID		= NULL;
	CCol				col;
	DBID				ReferencedTableID;

	// create support for foreign key constraint
	TESTC_(ReferencedTable.CreateTable(0, 0), S_OK);
	ReferencedTable.AddInfoFromColumnsSchemaRowset(m_pITDWC, ReferencedTable.GetTableName());

	DuplicateColumnDesc(m_rgColumnDesc, m_cColumnDesc, &rgColumnDesc);
	cColumnDesc = m_cColumnDesc;
	TESTC_PROVIDER(DBKIND_NAME == rgColumnDesc[0].dbcid.eKind
		&& rgColumnDesc[0].dbcid.uName.pwszName);

	// set up the check constraint
	ReferencedTableID.eKind				= DBKIND_NAME;
	ReferencedTableID.uName.pwszName	= NULL;
	consForeignKey.SetReferencedTableID(&ReferencedTableID);

	consForeignKey.AddForeignKeyColumn(&rgColumnDesc[0].dbcid);
	TESTC_(ReferencedTable.GetColInfo(1, col), S_OK);
	consForeignKey.AddColumn(col.GetColID());
	
	CHECK(CreateAndCheckTableWithConstraints(
		m_pITDWC, NULL, NULL, 
		cColumnDesc, rgColumnDesc, 
		1, consForeignKey, 
		IID_IRowset, 0, NULL, 
		&pTableID, NULL), DB_E_NOTABLE);

CLEANUP:
	CHECK(ReferencedTable.DropTable(), S_OK);
	ReleaseColumnDesc(rgColumnDesc, cColumnDesc);
	ReleaseDBID(pTableID, TRUE);
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(14)
//*-----------------------------------------------------------------------
// @mfunc DB_NULLID *pReferencedTableID for a foreign key constraint
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCCreateTableWithConstraints_Boundary::Variation_14()
{ 
	TBEGIN
	CTable				ReferencedTable(m_pITDWC, (LPWSTR)gwszModuleName);
	CForeignKeyCons		consForeignKey(NULL, m_SupportedMatchType);
	DBCOLUMNDESC		*rgColumnDesc	= NULL;
	DBORDINAL			cColumnDesc		= 0;
	DBID				*pTableID		= NULL;
	CCol				col;

	// create support for foreign key constraint
	TESTC_(ReferencedTable.CreateTable(0, 0), S_OK);
	ReferencedTable.AddInfoFromColumnsSchemaRowset(m_pITDWC, ReferencedTable.GetTableName());

	DuplicateColumnDesc(m_rgColumnDesc, m_cColumnDesc, &rgColumnDesc);
	cColumnDesc = m_cColumnDesc;
	TESTC_PROVIDER(DBKIND_NAME == rgColumnDesc[0].dbcid.eKind
		&& rgColumnDesc[0].dbcid.uName.pwszName);

	// set up the check constraint
	consForeignKey.SetReferencedTableID((DBID*)&DB_NULLID);

	consForeignKey.AddForeignKeyColumn(&rgColumnDesc[0].dbcid);
	TESTC_(ReferencedTable.GetColInfo(1, col), S_OK);
	consForeignKey.AddColumn(col.GetColID());
	
	CHECK(CreateAndCheckTableWithConstraints(
		m_pITDWC, NULL, NULL, 
		cColumnDesc, rgColumnDesc, 
		1, consForeignKey, 
		IID_IRowset, 0, NULL, 
		&pTableID, NULL), DB_E_NOTABLE);

CLEANUP:
	CHECK(ReferencedTable.DropTable(), S_OK);
	ReleaseColumnDesc(rgColumnDesc, cColumnDesc);
	ReleaseDBID(pTableID, TRUE);
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(15)
//*-----------------------------------------------------------------------
// @mfunc Empty string referenced table name for a foreign key constraint
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCCreateTableWithConstraints_Boundary::Variation_15()
{ 
	TBEGIN
	CTable				ReferencedTable(m_pITDWC, (LPWSTR)gwszModuleName);
	CForeignKeyCons		consForeignKey(NULL, m_SupportedMatchType);
	DBCOLUMNDESC		*rgColumnDesc	= NULL;
	DBORDINAL			cColumnDesc		= 0;
	DBID				*pTableID		= NULL;
	CCol				col;
	DBID				ReferencedTableID;

	// create support for foreign key constraint
	TESTC_(ReferencedTable.CreateTable(0, 0), S_OK);
	ReferencedTable.AddInfoFromColumnsSchemaRowset(m_pITDWC, ReferencedTable.GetTableName());

	DuplicateColumnDesc(m_rgColumnDesc, m_cColumnDesc, &rgColumnDesc);
	cColumnDesc = m_cColumnDesc;
	TESTC_PROVIDER(DBKIND_NAME == rgColumnDesc[0].dbcid.eKind
		&& rgColumnDesc[0].dbcid.uName.pwszName);

	// set up the check constraint
	ReferencedTableID.eKind				= DBKIND_NAME;
	ReferencedTableID.uName.pwszName	= L"";
	consForeignKey.SetReferencedTableID(&ReferencedTableID);

	consForeignKey.AddForeignKeyColumn(&rgColumnDesc[0].dbcid);
	TESTC_(ReferencedTable.GetColInfo(1, col), S_OK);
	consForeignKey.AddColumn(col.GetColID());
	
	CHECK(CreateAndCheckTableWithConstraints(
		m_pITDWC, NULL, NULL, 
		cColumnDesc, rgColumnDesc, 
		1, consForeignKey, 
		IID_IRowset, 0, NULL, 
		&pTableID, NULL), DB_E_NOTABLE);

CLEANUP:
	CHECK(ReferencedTable.DropTable(), S_OK);
	ReleaseColumnDesc(rgColumnDesc, cColumnDesc);
	ReleaseDBID(pTableID, TRUE);
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(16)
//*-----------------------------------------------------------------------
// @mfunc Maximum length referenced table name for a foreign key constraint
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCCreateTableWithConstraints_Boundary::Variation_16()
{ 
	TBEGIN
	CTable				ReferencedTable(m_pITDWC, (LPWSTR)gwszModuleName);
	CForeignKeyCons		consForeignKey(NULL, m_SupportedMatchType);
	DBCOLUMNDESC		*rgColumnDesc	= NULL;
	DBORDINAL			cColumnDesc		= 0;
	DBID				*pTableID		= NULL;
	CCol				col;
	WCHAR				*pwszTableName	= NULL;
	CUniqueCons			cons;

	// create support for foreign key constraint
	ReferencedTable.MakeTableName(NULL);
	pwszTableName = BuildValidName(m_cMaxTableName, ReferencedTable.GetTableName());
	TESTC_(ReferencedTable.CreateTable(0, 0, pwszTableName), S_OK);
	ReferencedTable.AddInfoFromColumnsSchemaRowset(m_pITDWC, ReferencedTable.GetTableName());
	CHECK(AddUniqueConstraint(&ReferencedTable, 1), S_OK);

	DuplicateColumnDesc(m_rgColumnDesc, m_cColumnDesc, &rgColumnDesc);
	cColumnDesc = m_cColumnDesc;
	TESTC_PROVIDER(DBKIND_NAME == rgColumnDesc[0].dbcid.eKind
		&& rgColumnDesc[0].dbcid.uName.pwszName);

	// set up the check constraint
	consForeignKey.SetReferencedTableID(&ReferencedTable.GetTableID());

	consForeignKey.AddForeignKeyColumn(&rgColumnDesc[0].dbcid);
	TESTC_(ReferencedTable.GetColInfo(1, col), S_OK);
	consForeignKey.AddColumn(col.GetColID());
	
	CHECK(CreateAndCheckTableWithConstraints(
		m_pITDWC, NULL, NULL, 
		cColumnDesc, rgColumnDesc, 
		1, consForeignKey, 
		IID_IRowset, 0, NULL, 
		&pTableID, NULL), S_OK);

CLEANUP:
	CHECK(DropTableAndCheck(pTableID), S_OK);
	CHECK(ReferencedTable.DropTable(), S_OK);
	ReleaseColumnDesc(rgColumnDesc, cColumnDesc);
	ReleaseDBID(pTableID, TRUE);
	SAFE_FREE(pwszTableName);
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(17)
//*-----------------------------------------------------------------------
// @mfunc Referenced table name longer than allowed for a foreign key constraint
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCCreateTableWithConstraints_Boundary::Variation_17()
{ 
	TBEGIN
	CTable				ReferencedTable(m_pITDWC, (LPWSTR)gwszModuleName);
	CForeignKeyCons		consForeignKey(NULL, m_SupportedMatchType);
	DBCOLUMNDESC		*rgColumnDesc	= NULL;
	DBORDINAL			cColumnDesc		= 0;
	DBID				*pTableID		= NULL;
	CCol				col;
	DBID				ReferencedTableID;

	// create support for foreign key constraint
	ReferencedTable.MakeTableName(NULL);
	ReferencedTableID.eKind				= DBKIND_NAME;
	ReferencedTableID.uName.pwszName	= BuildValidName(m_cMaxTableName+1, ReferencedTable.GetTableName());
	TESTC_(ReferencedTable.CreateTable(0, 0), S_OK);
	ReferencedTable.AddInfoFromColumnsSchemaRowset(m_pITDWC, ReferencedTable.GetTableName());

	DuplicateColumnDesc(m_rgColumnDesc, m_cColumnDesc, &rgColumnDesc);
	cColumnDesc = m_cColumnDesc;
	TESTC_PROVIDER(DBKIND_NAME == rgColumnDesc[0].dbcid.eKind
		&& rgColumnDesc[0].dbcid.uName.pwszName);

	// set up the check constraint
	consForeignKey.SetReferencedTableID(&ReferencedTableID);

	consForeignKey.AddForeignKeyColumn(&rgColumnDesc[0].dbcid);
	TESTC_(ReferencedTable.GetColInfo(1, col), S_OK);
	consForeignKey.AddColumn(col.GetColID());
	
	TESTC_(CreateAndCheckTableWithConstraints(
		m_pITDWC, NULL, NULL, 
		cColumnDesc, rgColumnDesc, 
		1, consForeignKey, 
		IID_IRowset, 0, NULL, 
		&pTableID, NULL), DB_E_NOTABLE);

CLEANUP:
	CHECK(ReferencedTable.DropTable(), S_OK);
	ReleaseColumnDesc(rgColumnDesc, cColumnDesc);
	ReleaseDBID(pTableID, TRUE);
	ReleaseDBID(&ReferencedTableID, FALSE);
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(18)
//*-----------------------------------------------------------------------
// @mfunc Illegal characters in the referenced table name for a foreign key constraint
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCCreateTableWithConstraints_Boundary::Variation_18()
{ 
	TBEGIN
	CTable				ReferencedTable(m_pITDWC, (LPWSTR)gwszModuleName);
	CForeignKeyCons		consForeignKey(NULL, m_SupportedMatchType);
	DBCOLUMNDESC		*rgColumnDesc	= NULL;
	DBORDINAL			cColumnDesc		= 0;
	DBID				*pTableID		= NULL;
	CCol				col;
	DBID				ReferencedTableID;
	size_t				m, n;

	// create support for foreign key constraint
	ReferencedTable.MakeTableName(NULL);
	ReferencedTableID.eKind				= DBKIND_NAME;
	m = min(m_cMaxTableName, n=5+wcslen(ReferencedTable.GetTableName()));
	ReferencedTableID.uName.pwszName	= BuildInvalidName(m, ReferencedTable.GetTableName(), m_pwszInvalidTableChars);
	TESTC_(ReferencedTable.CreateTable(0, 0), S_OK);
	ReferencedTable.AddInfoFromColumnsSchemaRowset(m_pITDWC, ReferencedTable.GetTableName());

	DuplicateColumnDesc(m_rgColumnDesc, m_cColumnDesc, &rgColumnDesc);
	cColumnDesc = m_cColumnDesc;
	TESTC_PROVIDER(DBKIND_NAME == rgColumnDesc[0].dbcid.eKind
		&& rgColumnDesc[0].dbcid.uName.pwszName);

	// set up the check constraint
	consForeignKey.SetReferencedTableID(&ReferencedTableID);

	consForeignKey.AddForeignKeyColumn(&rgColumnDesc[0].dbcid);
	TESTC_(ReferencedTable.GetColInfo(1, col), S_OK);
	consForeignKey.AddColumn(col.GetColID());
	
	TESTC_(CreateAndCheckTableWithConstraints(
		m_pITDWC, NULL, NULL, 
		cColumnDesc, rgColumnDesc, 
		1, consForeignKey, 
		IID_IRowset, 0, NULL, 
		&pTableID, NULL), DB_E_NOTABLE);

CLEANUP:
	CHECK(ReferencedTable.DropTable(), S_OK);
	ReleaseColumnDesc(rgColumnDesc, cColumnDesc);
	ReleaseDBID(pTableID, TRUE);
	ReleaseDBID(&ReferencedTableID, FALSE);
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(19)
//*-----------------------------------------------------------------------
// @mfunc Bad constraint type
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCCreateTableWithConstraints_Boundary::Variation_19()
{ 
	TBEGIN
	DBCOLUMNDESC		*rgColumnDesc	= NULL;
	DBORDINAL			cColumnDesc		= 0;
	DBID				*pTableID		= NULL;
	DBCONSTRAINTDESC	ConsDesc;

	DuplicateColumnDesc(m_rgColumnDesc, m_cColumnDesc, &rgColumnDesc);
	cColumnDesc = m_cColumnDesc;

	// set up the check constraint
	memset(&ConsDesc, 0, sizeof(DBCONSTRAINTDESC));
	ConsDesc.ConstraintType = 0x4b;

	TESTC_(CreateAndCheckTableWithConstraints(
		m_pITDWC, NULL, NULL, 
		cColumnDesc, rgColumnDesc, 
		1, &ConsDesc, 
		IID_IRowset, 0, NULL, 
		&pTableID, NULL), DB_E_BADCONSTRAINTTYPE);

CLEANUP:
	ReleaseColumnDesc(rgColumnDesc, cColumnDesc);
	ReleaseDBID(pTableID, TRUE);
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(20)
//*-----------------------------------------------------------------------
// @mfunc Inexistent referenced table
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCCreateTableWithConstraints_Boundary::Variation_20()
{ 
	TBEGIN
	CTable				ReferencedTable(m_pITDWC, (LPWSTR)gwszModuleName);
	CForeignKeyCons		consForeignKey(NULL, m_SupportedMatchType);
	DBCOLUMNDESC		*rgColumnDesc	= NULL;
	DBORDINAL			cColumnDesc		= 0;
	DBID				*pTableID		= NULL;

	// create support for foreign key constraint
	ReferencedTable.MakeTableName(NULL);

	DuplicateColumnDesc(m_rgColumnDesc, m_cColumnDesc, &rgColumnDesc);
	cColumnDesc = m_cColumnDesc;
	TESTC_PROVIDER(DBKIND_NAME == rgColumnDesc[0].dbcid.eKind
		&& rgColumnDesc[0].dbcid.uName.pwszName);

	// set up the check constraint
	consForeignKey.SetReferencedTableID(&ReferencedTable.GetTableID());

	consForeignKey.AddColumn(&rgColumnDesc[0].dbcid);
	consForeignKey.AddForeignKeyColumn(&rgColumnDesc[0].dbcid);
	
	CHECK(CreateAndCheckTableWithConstraints(
		m_pITDWC, NULL, NULL, 
		cColumnDesc, rgColumnDesc, 
		1, consForeignKey, 
		IID_IRowset, 0, NULL, 
		&pTableID, NULL), DB_E_NOTABLE);

CLEANUP:
	ReleaseColumnDesc(rgColumnDesc, cColumnDesc);
	ReleaseDBID(pTableID, TRUE);
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(21)
//*-----------------------------------------------------------------------
// @mfunc Empty string for a column name
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCCreateTableWithConstraints_Boundary::Variation_21()
{ 
	TBEGIN
	CTable			ReferencedTable(m_pThisTestModule->m_pIUnknown2, (LPWSTR)gwszModuleName);
	DBID			TableID;
	DBCOLUMNDESC	*rgColumnDesc	= NULL;
	DBORDINAL		cColumnDesc		= 0;
	CUniqueCons		consUnique;
	CPrimaryKeyCons	consPrimaryKey;
	CForeignKeyCons	consForeignKey(NULL, m_SupportedMatchType);
	DBORDINAL		rgReferencedCol[] = {1};
	CCol			col;
	DBID			colid;

	colid.eKind				= DBKIND_NAME;
	colid.uName.pwszName	= L"";

	DuplicateColumnDesc(m_rgColumnDesc, m_cColumnDesc, &rgColumnDesc);
	cColumnDesc = m_cColumnDesc;
	// release the properties on all column and make the first column not nullable
	ReleaseAllColumnPropSets(rgColumnDesc, cColumnDesc);
	SetProperty(&rgColumnDesc[0].rgPropertySets, &rgColumnDesc[0].cPropertySets,
			DBPROP_COL_NULLABLE, 
			VT_BOOL, (LPVOID)VARIANT_FALSE, 
			DBPROPOPTIONS_REQUIRED);

	m_pTable->MakeTableName(NULL);
	TableID.eKind			= DBKIND_NAME;
	TableID.uName.pwszName	= m_pTable->GetTableName();

	// create support for foreign key constraint
	TESTC_(ReferencedTable.CreateTable(0, 0), S_OK);
	ReferencedTable.AddInfoFromColumnsSchemaRowset(m_pITDWC, ReferencedTable.GetTableName());
	// make the referenced columns unique
	TESTC_(AddUniqueConstraint(&ReferencedTable, rgReferencedCol[0], (DBDEFERRABILITY)0), S_OK);

	// set a unique constraint on the second column
	consUnique.AddColumn(&colid);
	CHECK(CreateAndCheckTableWithConstraints(m_pITDWC, NULL, &TableID, cColumnDesc, rgColumnDesc, 
		1, consUnique, 
		IID_IRowset, 0, NULL, NULL, NULL), DB_E_NOCOLUMN);

	// set a primary key on the first column of the table
	consPrimaryKey.AddColumn(&colid);
	CHECK(CreateAndCheckTableWithConstraints(m_pITDWC, NULL, &TableID, cColumnDesc, rgColumnDesc, 
		1, consPrimaryKey, 
		IID_IRowset, 0, NULL, NULL, NULL), DB_E_NOCOLUMN);

	// set a simple foreign key constraint
	TESTC_(ReferencedTable.GetColInfo(1, col), S_OK);
	consForeignKey.AddColumn(col.GetColID());
	consForeignKey.AddForeignKeyColumn(&colid);
	consForeignKey.SetReferencedTableID(&ReferencedTable.GetTableID());
	CHECK(CreateAndCheckTableWithConstraints(m_pITDWC, NULL, &TableID, cColumnDesc, rgColumnDesc, 
		1, consForeignKey, 
		IID_IRowset, 0, NULL, NULL, NULL), DB_E_NOCOLUMN);
	
CLEANUP:
	CHECK(ReferencedTable.DropTable(), S_OK);
	ReleaseColumnDesc(rgColumnDesc, cColumnDesc);
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(22)
//*-----------------------------------------------------------------------
// @mfunc Maximum length column name in a constraint
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCCreateTableWithConstraints_Boundary::Variation_22()
{ 
	TBEGIN
	CTable			ReferencedTable(m_pThisTestModule->m_pIUnknown2, (LPWSTR)gwszModuleName);
	DBID			*pTableID = NULL;
	DBCOLUMNDESC	*rgColumnDesc	= NULL;
	DBORDINAL		cColumnDesc		= 0;
	CUniqueCons		consUnique;
	CPrimaryKeyCons	consPrimaryKey;
	CForeignKeyCons	consForeignKey(NULL, m_SupportedMatchType);
	DBORDINAL		rgReferencedCol[] = {1};
	CCol			col;
	WCHAR			*pwszColName = NULL;


	DuplicateColumnDesc(m_rgColumnDesc, m_cColumnDesc, &rgColumnDesc);
	cColumnDesc = m_cColumnDesc;
	// release the properties on all column and make the first column not nullable
	ReleaseAllColumnPropSets(rgColumnDesc, cColumnDesc);
	SetProperty(&rgColumnDesc[0].rgPropertySets, &rgColumnDesc[0].cPropertySets,
			DBPROP_COL_NULLABLE, 
			VT_BOOL, (LPVOID)VARIANT_FALSE, 
			DBPROPOPTIONS_REQUIRED);

	// build the column name
	TESTC_PROVIDER(DBKIND_NAME == rgColumnDesc[0].dbcid.eKind);
	pwszColName = rgColumnDesc[0].dbcid.uName.pwszName;
	rgColumnDesc[0].dbcid.uName.pwszName	= BuildValidName(m_cMaxColName, pwszColName);

	// create support for foreign key constraint
	TESTC_(ReferencedTable.CreateTable(0, 0), S_OK);
	ReferencedTable.AddInfoFromColumnsSchemaRowset(m_pITDWC, ReferencedTable.GetTableName());
	// make the referenced columns unique
	TESTC_(AddUniqueConstraint(&ReferencedTable, rgReferencedCol[0], (DBDEFERRABILITY)0), S_OK);

	// set a unique constraint on the second column
	consUnique.AddColumn(&rgColumnDesc[0].dbcid);
	CHECK(CreateAndCheckTableWithConstraints(m_pITDWC, NULL, NULL, 
		cColumnDesc, rgColumnDesc, 
		1, consUnique, 
		IID_IRowset, 0, NULL, &pTableID, NULL), S_OK);
	CHECK(DropTableAndCheck(pTableID), S_OK);
	ReleaseDBID(pTableID, TRUE);

	// set a primary key on the first column of the table
	consPrimaryKey.AddColumn(&rgColumnDesc[0].dbcid);
	CHECK(CreateAndCheckTableWithConstraints(m_pITDWC, NULL, NULL, 
		cColumnDesc, rgColumnDesc, 
		1, consPrimaryKey, 
		IID_IRowset, 0, NULL, &pTableID, NULL), S_OK);
	CHECK(DropTableAndCheck(pTableID), S_OK);
	ReleaseDBID(pTableID, TRUE);

	// set a simple foreign key constraint
	TESTC_(ReferencedTable.GetColInfo(1, col), S_OK);
	consForeignKey.AddColumn(col.GetColID());
	consForeignKey.AddForeignKeyColumn(&rgColumnDesc[0].dbcid);
	consForeignKey.SetReferencedTableID(&ReferencedTable.GetTableID());
	CHECK(CreateAndCheckTableWithConstraints(m_pITDWC, NULL, NULL, 
		cColumnDesc, rgColumnDesc, 
		1, consForeignKey, 
		IID_IRowset, 0, NULL, &pTableID, NULL), S_OK);
	CHECK(DropTableAndCheck(pTableID), S_OK);
	ReleaseDBID(pTableID, TRUE);
	
CLEANUP:
	CHECK(ReferencedTable.DropTable(), S_OK);
	ReleaseColumnDesc(rgColumnDesc, cColumnDesc);
	SAFE_FREE(pwszColName);
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(23)
//*-----------------------------------------------------------------------
// @mfunc Invalid DBKIND for a column DBID of a constraint
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCCreateTableWithConstraints_Boundary::Variation_23()
{ 
	TBEGIN
	CTable			ReferencedTable(m_pThisTestModule->m_pIUnknown2, (LPWSTR)gwszModuleName);
	DBID			*pTableID = NULL;
	DBCOLUMNDESC	*rgColumnDesc	= NULL;
	DBORDINAL		cColumnDesc		= 0;
	CUniqueCons		consUnique;
	CPrimaryKeyCons	consPrimaryKey;
	CForeignKeyCons	consForeignKey(NULL, m_SupportedMatchType);
	DBORDINAL		rgReferencedCol[] = {1};
	CCol			col;
	DBID			dbcid;

	dbcid.eKind = 0x3c;

	DuplicateColumnDesc(m_rgColumnDesc, m_cColumnDesc, &rgColumnDesc);
	cColumnDesc = m_cColumnDesc;
	// release the properties on all column and make the first column not nullable
	ReleaseAllColumnPropSets(rgColumnDesc, cColumnDesc);
	SetProperty(&rgColumnDesc[0].rgPropertySets, &rgColumnDesc[0].cPropertySets,
			DBPROP_COL_NULLABLE, 
			VT_BOOL, (LPVOID)VARIANT_FALSE, 
			DBPROPOPTIONS_REQUIRED);

	// create support for foreign key constraint
	TESTC_(ReferencedTable.CreateTable(0, 0), S_OK);
	ReferencedTable.AddInfoFromColumnsSchemaRowset(m_pITDWC, ReferencedTable.GetTableName());
	// make the referenced columns unique
	TESTC_(AddUniqueConstraint(&ReferencedTable, rgReferencedCol[0], (DBDEFERRABILITY)0), S_OK);

	// set a unique constraint on the second column
	((DBCONSTRAINTDESC*)consUnique)->cColumns		= 1;
	((DBCONSTRAINTDESC*)consUnique)->rgColumnList	= &dbcid;
	CHECK(CreateAndCheckTableWithConstraints(m_pITDWC, NULL, NULL, 
		cColumnDesc, rgColumnDesc, 
		1, consUnique, 
		IID_IRowset, 0, NULL, &pTableID, NULL), DB_E_NOCOLUMN);

	// set a primary key on the first column of the table
	((DBCONSTRAINTDESC*)consPrimaryKey)->cColumns		= 1;
	((DBCONSTRAINTDESC*)consPrimaryKey)->rgColumnList	= &dbcid;
	CHECK(CreateAndCheckTableWithConstraints(m_pITDWC, NULL, NULL, 
		cColumnDesc, rgColumnDesc, 
		1, consPrimaryKey, 
		IID_IRowset, 0, NULL, &pTableID, NULL), DB_E_NOCOLUMN);

	// set a simple foreign key constraint
	TESTC_(ReferencedTable.GetColInfo(1, col), S_OK);
	consForeignKey.AddColumn(col.GetColID());
	((DBCONSTRAINTDESC*)consForeignKey)->cForeignKeyColumns		= 1;
	((DBCONSTRAINTDESC*)consForeignKey)->rgForeignKeyColumnList	= &dbcid;
	consForeignKey.SetReferencedTableID(&ReferencedTable.GetTableID());
	CHECK(CreateAndCheckTableWithConstraints(m_pITDWC, NULL, NULL, 
		cColumnDesc, rgColumnDesc, 
		1, consForeignKey, 
		IID_IRowset, 0, NULL, &pTableID, NULL), DB_E_NOCOLUMN);
	
CLEANUP:
	((DBCONSTRAINTDESC*)consUnique)->cColumns			= 0;
	((DBCONSTRAINTDESC*)consUnique)->rgColumnList		= NULL;
	((DBCONSTRAINTDESC*)consPrimaryKey)->cColumns		= 0;
	((DBCONSTRAINTDESC*)consPrimaryKey)->rgColumnList	= NULL;
	((DBCONSTRAINTDESC*)consForeignKey)->cForeignKeyColumns		= 0;
	((DBCONSTRAINTDESC*)consForeignKey)->rgForeignKeyColumnList	= NULL;
	CHECK(ReferencedTable.DropTable(), S_OK);
	ReleaseColumnDesc(rgColumnDesc, cColumnDesc);
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(24)
//*-----------------------------------------------------------------------
// @mfunc Column ID is DB_NULLID
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCCreateTableWithConstraints_Boundary::Variation_24()
{ 
	TBEGIN
	CTable			ReferencedTable(m_pThisTestModule->m_pIUnknown2, (LPWSTR)gwszModuleName);
	DBID			*pTableID = NULL;
	DBCOLUMNDESC	*rgColumnDesc	= NULL;
	DBORDINAL		cColumnDesc		= 0;
	CUniqueCons		consUnique;
	CPrimaryKeyCons	consPrimaryKey;
	CForeignKeyCons	consForeignKey(NULL, m_SupportedMatchType);
	DBORDINAL		rgReferencedCol[] = {1};
	CCol			col;
	WCHAR			*pwszColName = NULL;

	DuplicateColumnDesc(m_rgColumnDesc, m_cColumnDesc, &rgColumnDesc);
	cColumnDesc = m_cColumnDesc;
	// release the properties on all column and make the first column not nullable
	ReleaseAllColumnPropSets(rgColumnDesc, cColumnDesc);
	SetProperty(&rgColumnDesc[0].rgPropertySets, &rgColumnDesc[0].cPropertySets,
			DBPROP_COL_NULLABLE, 
			VT_BOOL, (LPVOID)VARIANT_FALSE, 
			DBPROPOPTIONS_REQUIRED);

	// build the column name
	TESTC_PROVIDER(DBKIND_NAME == rgColumnDesc[0].dbcid.eKind);
	pwszColName = rgColumnDesc[0].dbcid.uName.pwszName;
	rgColumnDesc[0].dbcid.uName.pwszName	= BuildValidName(m_cMaxColName, pwszColName);

	// create support for foreign key constraint
	TESTC_(ReferencedTable.CreateTable(0, 0), S_OK);
	ReferencedTable.AddInfoFromColumnsSchemaRowset(m_pITDWC, ReferencedTable.GetTableName());
	// make the referenced columns unique
	TESTC_(AddUniqueConstraint(&ReferencedTable, rgReferencedCol[0], (DBDEFERRABILITY)0), S_OK);

	// set a unique constraint on column DB_NULLID
	consUnique.AddColumn((DBID*)&DB_NULLID);
	CHECK(CreateAndCheckTableWithConstraints(m_pITDWC, NULL, NULL, 
		cColumnDesc, rgColumnDesc, 
		1, consUnique, 
		IID_IRowset, 0, NULL, &pTableID, NULL), DB_E_NOCOLUMN);

	// set a primary key on DB_NULLID
	consPrimaryKey.AddColumn((DBID*)&DB_NULLID);
	CHECK(CreateAndCheckTableWithConstraints(m_pITDWC, NULL, NULL, 
		cColumnDesc, rgColumnDesc, 
		1, consPrimaryKey, 
		IID_IRowset, 0, NULL, &pTableID, NULL), DB_E_NOCOLUMN);

	// set a simple foreign key constraint
	TESTC_(ReferencedTable.GetColInfo(1, col), S_OK);
	consForeignKey.AddColumn(col.GetColID());
	consForeignKey.AddForeignKeyColumn((DBID*)&DB_NULLID);
	consForeignKey.SetReferencedTableID(&ReferencedTable.GetTableID());
	CHECK(CreateAndCheckTableWithConstraints(m_pITDWC, NULL, NULL, 
		cColumnDesc, rgColumnDesc, 
		1, consForeignKey, 
		IID_IRowset, 0, NULL, &pTableID, NULL), DB_E_NOCOLUMN);
	
CLEANUP:
	CHECK(ReferencedTable.DropTable(), S_OK);
	ReleaseColumnDesc(rgColumnDesc, cColumnDesc);
	SAFE_FREE(pwszColName);
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(25)
//*-----------------------------------------------------------------------
// @mfunc Inexistent column => DB_E_NOCOLUMN
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCCreateTableWithConstraints_Boundary::Variation_25()
{ 
	TBEGIN
	CTable			ReferencedTable(m_pThisTestModule->m_pIUnknown2, (LPWSTR)gwszModuleName);
	DBID			*pTableID = NULL;
	DBCOLUMNDESC	*rgColumnDesc	= NULL;
	DBORDINAL		cColumnDesc		= 0;
	CUniqueCons		consUnique;
	CPrimaryKeyCons	consPrimaryKey;
	CForeignKeyCons	consForeignKey(NULL, m_SupportedMatchType);
	DBORDINAL		rgReferencedCol[] = {1};
	CCol			col;

	DuplicateColumnDesc(m_rgColumnDesc, m_cColumnDesc, &rgColumnDesc);
	cColumnDesc = m_cColumnDesc-1;
	TESTC_PROVIDER(1 < m_cColumnDesc);

	// release the properties on all column and make the first column not nullable
	ReleaseAllColumnPropSets(rgColumnDesc, cColumnDesc);
	SetProperty(&rgColumnDesc[0].rgPropertySets, &rgColumnDesc[0].cPropertySets,
			DBPROP_COL_NULLABLE, 
			VT_BOOL, (LPVOID)VARIANT_FALSE, 
			DBPROPOPTIONS_REQUIRED);

	// create support for foreign key constraint
	TESTC_(ReferencedTable.CreateTable(0, 0), S_OK);
	ReferencedTable.AddInfoFromColumnsSchemaRowset(m_pITDWC, ReferencedTable.GetTableName());
	// make the referenced columns unique
	TESTC_(AddUniqueConstraint(&ReferencedTable, rgReferencedCol[0], (DBDEFERRABILITY)0), S_OK);

	// set a unique constraint on the second column
	consUnique.AddColumn(&rgColumnDesc[cColumnDesc].dbcid);
	CHECK(CreateAndCheckTableWithConstraints(m_pITDWC, NULL, NULL, 
		cColumnDesc, rgColumnDesc, 
		1, consUnique, 
		IID_IRowset, 0, NULL, &pTableID, NULL), DB_E_NOCOLUMN);

	// set a primary key on the first column of the table
	consPrimaryKey.AddColumn(&rgColumnDesc[cColumnDesc].dbcid);
	CHECK(CreateAndCheckTableWithConstraints(m_pITDWC, NULL, NULL, 
		cColumnDesc, rgColumnDesc, 
		1, consPrimaryKey, 
		IID_IRowset, 0, NULL, &pTableID, NULL), DB_E_NOCOLUMN);

	// set a simple foreign key constraint
	TESTC_(ReferencedTable.GetColInfo(1, col), S_OK);
	consForeignKey.AddColumn(col.GetColID());
	consForeignKey.AddForeignKeyColumn(&rgColumnDesc[cColumnDesc].dbcid);
	consForeignKey.SetReferencedTableID(&ReferencedTable.GetTableID());
	CHECK(CreateAndCheckTableWithConstraints(m_pITDWC, NULL, NULL, 
		cColumnDesc, rgColumnDesc, 
		1, consForeignKey, 
		IID_IRowset, 0, NULL, &pTableID, NULL), DB_E_NOCOLUMN);
	
CLEANUP:
	CHECK(ReferencedTable.DropTable(), S_OK);
	cColumnDesc = m_cColumnDesc;
	ReleaseColumnDesc(rgColumnDesc, cColumnDesc);
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(26)
//*-----------------------------------------------------------------------
// @mfunc NULL column name => DB_E_NOCOLUMN
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCCreateTableWithConstraints_Boundary::Variation_26()
{ 
	TBEGIN
	CTable			ReferencedTable(m_pThisTestModule->m_pIUnknown2, (LPWSTR)gwszModuleName);
	DBID			*pTableID = NULL;
	DBCOLUMNDESC	*rgColumnDesc	= NULL;
	DBORDINAL		cColumnDesc		= 0;
	CUniqueCons		consUnique;
	CPrimaryKeyCons	consPrimaryKey;
	CForeignKeyCons	consForeignKey(NULL, m_SupportedMatchType);
	DBORDINAL		rgReferencedCol[] = {1};
	CCol			col;
	DBID			dbcid;

	dbcid.eKind				= DBKIND_NAME;
	dbcid.uName.pwszName	= NULL;

	DuplicateColumnDesc(m_rgColumnDesc, m_cColumnDesc, &rgColumnDesc);
	cColumnDesc = m_cColumnDesc;
	// release the properties on all column and make the first column not nullable
	ReleaseAllColumnPropSets(rgColumnDesc, cColumnDesc);
	SetProperty(&rgColumnDesc[0].rgPropertySets, &rgColumnDesc[0].cPropertySets,
			DBPROP_COL_NULLABLE, 
			VT_BOOL, (LPVOID)VARIANT_FALSE, 
			DBPROPOPTIONS_REQUIRED);

	// create support for foreign key constraint
	TESTC_(ReferencedTable.CreateTable(0, 0), S_OK);
	ReferencedTable.AddInfoFromColumnsSchemaRowset(m_pITDWC, ReferencedTable.GetTableName());
	// make the referenced columns unique
	TESTC_(AddUniqueConstraint(&ReferencedTable, rgReferencedCol[0], (DBDEFERRABILITY)0), S_OK);

	// set a unique constraint on the second column
	consUnique.AddColumn(&dbcid);
	CHECK(CreateAndCheckTableWithConstraints(m_pITDWC, NULL, NULL, 
		cColumnDesc, rgColumnDesc, 
		1, consUnique, 
		IID_IRowset, 0, NULL, &pTableID, NULL), DB_E_NOCOLUMN);

	// set a primary key on the first column of the table
	consPrimaryKey.AddColumn(&dbcid);
	CHECK(CreateAndCheckTableWithConstraints(m_pITDWC, NULL, NULL, 
		cColumnDesc, rgColumnDesc, 
		1, consPrimaryKey, 
		IID_IRowset, 0, NULL, &pTableID, NULL), DB_E_NOCOLUMN);

	// set a simple foreign key constraint
	TESTC_(ReferencedTable.GetColInfo(1, col), S_OK);
	consForeignKey.AddColumn(col.GetColID());
	consForeignKey.AddForeignKeyColumn(&dbcid);
	consForeignKey.SetReferencedTableID(&ReferencedTable.GetTableID());
	CHECK(CreateAndCheckTableWithConstraints(m_pITDWC, NULL, NULL, 
		cColumnDesc, rgColumnDesc, 
		1, consForeignKey, 
		IID_IRowset, 0, NULL, &pTableID, NULL), DB_E_NOCOLUMN);
	
CLEANUP:
	CHECK(ReferencedTable.DropTable(), S_OK);
	ReleaseColumnDesc(rgColumnDesc, cColumnDesc);
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(27)
//*-----------------------------------------------------------------------
// @mfunc Column name exceeds maximum length name
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCCreateTableWithConstraints_Boundary::Variation_27()
{ 
	TBEGIN
	CTable			ReferencedTable(m_pThisTestModule->m_pIUnknown2, (LPWSTR)gwszModuleName);
	DBID			*pTableID = NULL;
	DBCOLUMNDESC	*rgColumnDesc	= NULL;
	DBORDINAL		cColumnDesc		= 0;
	CUniqueCons		consUnique;
	CPrimaryKeyCons	consPrimaryKey;
	CForeignKeyCons	consForeignKey(NULL, m_SupportedMatchType);
	DBORDINAL		rgReferencedCol[] = {1};
	CCol			col;
	DBID			dbcid;

	DuplicateColumnDesc(m_rgColumnDesc, m_cColumnDesc, &rgColumnDesc);
	cColumnDesc = m_cColumnDesc;
	// release the properties on all column and make the first column not nullable
	ReleaseAllColumnPropSets(rgColumnDesc, cColumnDesc);
	SetProperty(&rgColumnDesc[0].rgPropertySets, &rgColumnDesc[0].cPropertySets,
			DBPROP_COL_NULLABLE, 
			VT_BOOL, (LPVOID)VARIANT_FALSE, 
			DBPROPOPTIONS_REQUIRED);

	TESTC_PROVIDER(DBKIND_NAME == rgColumnDesc[0].dbcid.eKind);
	dbcid.eKind				= DBKIND_NAME;
	dbcid.uName.pwszName	= BuildValidName(m_cMaxColName+1, rgColumnDesc[0].dbcid.uName.pwszName);

	// create support for foreign key constraint
	TESTC_(ReferencedTable.CreateTable(0, 0), S_OK);
	ReferencedTable.AddInfoFromColumnsSchemaRowset(m_pITDWC, ReferencedTable.GetTableName());
	// make the referenced columns unique
	TESTC_(AddUniqueConstraint(&ReferencedTable, rgReferencedCol[0], (DBDEFERRABILITY)0), S_OK);

	// set a unique constraint on the second column
	consUnique.AddColumn(&dbcid);
	CHECK(CreateAndCheckTableWithConstraints(m_pITDWC, NULL, NULL, 
		cColumnDesc, rgColumnDesc, 
		1, consUnique, 
		IID_IRowset, 0, NULL, &pTableID, NULL), DB_E_NOCOLUMN);

	// set a primary key on the first column of the table
	consPrimaryKey.AddColumn(&dbcid);
	CHECK(CreateAndCheckTableWithConstraints(m_pITDWC, NULL, NULL, 
		cColumnDesc, rgColumnDesc, 
		1, consPrimaryKey, 
		IID_IRowset, 0, NULL, &pTableID, NULL), DB_E_NOCOLUMN);

	// set a simple foreign key constraint
	TESTC_(ReferencedTable.GetColInfo(1, col), S_OK);
	consForeignKey.AddColumn(col.GetColID());
	consForeignKey.AddForeignKeyColumn(&dbcid);
	consForeignKey.SetReferencedTableID(&ReferencedTable.GetTableID());
	CHECK(CreateAndCheckTableWithConstraints(m_pITDWC, NULL, NULL, 
		cColumnDesc, rgColumnDesc, 
		1, consForeignKey, 
		IID_IRowset, 0, NULL, &pTableID, NULL), DB_E_NOCOLUMN);
	
CLEANUP:
	CHECK(ReferencedTable.DropTable(), S_OK);
	ReleaseColumnDesc(rgColumnDesc, cColumnDesc);
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(28)
//*-----------------------------------------------------------------------
// @mfunc Invalid column name
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCCreateTableWithConstraints_Boundary::Variation_28()
{ 
	TBEGIN
	CTable			ReferencedTable(m_pThisTestModule->m_pIUnknown2, (LPWSTR)gwszModuleName);
	DBID			*pTableID = NULL;
	DBCOLUMNDESC	*rgColumnDesc	= NULL;
	DBORDINAL		cColumnDesc		= 0;
	CUniqueCons		consUnique;
	CPrimaryKeyCons	consPrimaryKey;
	CForeignKeyCons	consForeignKey(NULL, m_SupportedMatchType);
	DBORDINAL		rgReferencedCol[] = {1};
	CCol			col;
	DBID			dbcid;
	size_t			m, n;

	DuplicateColumnDesc(m_rgColumnDesc, m_cColumnDesc, &rgColumnDesc);
	cColumnDesc = m_cColumnDesc;
	// release the properties on all column and make the first column not nullable
	ReleaseAllColumnPropSets(rgColumnDesc, cColumnDesc);
	SetProperty(&rgColumnDesc[0].rgPropertySets, &rgColumnDesc[0].cPropertySets,
			DBPROP_COL_NULLABLE, 
			VT_BOOL, (LPVOID)VARIANT_FALSE, 
			DBPROPOPTIONS_REQUIRED);

	TESTC_PROVIDER(DBKIND_NAME == rgColumnDesc[0].dbcid.eKind);
	m = min(m_cMaxColName, n=5+wcslen(rgColumnDesc[0].dbcid.uName.pwszName));
	dbcid.eKind				= DBKIND_NAME;
	dbcid.uName.pwszName	= BuildInvalidName(m, rgColumnDesc[0].dbcid.uName.pwszName, m_pwszInvalidColChars);

	// create support for foreign key constraint
	TESTC_(ReferencedTable.CreateTable(0, 0), S_OK);
	ReferencedTable.AddInfoFromColumnsSchemaRowset(m_pITDWC, ReferencedTable.GetTableName());
	// make the referenced columns unique
	TESTC_(AddUniqueConstraint(&ReferencedTable, rgReferencedCol[0], (DBDEFERRABILITY)0), S_OK);

	// set a unique constraint on the second column
	consUnique.AddColumn(&dbcid);
	CHECK(CreateAndCheckTableWithConstraints(m_pITDWC, NULL, NULL, 
		cColumnDesc, rgColumnDesc, 
		1, consUnique, 
		IID_IRowset, 0, NULL, &pTableID, NULL), DB_E_NOCOLUMN);

	// set a primary key on the first column of the table
	consPrimaryKey.AddColumn(&dbcid);
	CHECK(CreateAndCheckTableWithConstraints(m_pITDWC, NULL, NULL, 
		cColumnDesc, rgColumnDesc, 
		1, consPrimaryKey, 
		IID_IRowset, 0, NULL, &pTableID, NULL), DB_E_NOCOLUMN);

	// set a simple foreign key constraint
	TESTC_(ReferencedTable.GetColInfo(1, col), S_OK);
	consForeignKey.AddColumn(col.GetColID());
	consForeignKey.AddForeignKeyColumn(&dbcid);
	consForeignKey.SetReferencedTableID(&ReferencedTable.GetTableID());
	CHECK(CreateAndCheckTableWithConstraints(m_pITDWC, NULL, NULL, 
		cColumnDesc, rgColumnDesc, 
		1, consForeignKey, 
		IID_IRowset, 0, NULL, &pTableID, NULL), DB_E_NOCOLUMN);
	
CLEANUP:
	CHECK(ReferencedTable.DropTable(), S_OK);
	ReleaseColumnDesc(rgColumnDesc, cColumnDesc);
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(29)
//*-----------------------------------------------------------------------
// @mfunc Existent table name => DB_E_DUPLICATETABLEID
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCCreateTableWithConstraints_Boundary::Variation_29()
{ 
	TBEGIN
	CTable			ReferencedTable(m_pThisTestModule->m_pIUnknown2, (LPWSTR)gwszModuleName);
	DBID			TableID;
	DBCOLUMNDESC	*rgColumnDesc	= NULL;
	DBORDINAL		cColumnDesc		= 0;
	CConsDescArray	ConsDescArray;
	CUniqueCons		consUnique;
	CPrimaryKeyCons	consPrimaryKey;
	CForeignKeyCons	consForeignKey(NULL, m_SupportedMatchType);
	DBORDINAL		rgReferencedCol[] = {1};
	CCol			col;

	DuplicateColumnDesc(m_rgColumnDesc, m_cColumnDesc, &rgColumnDesc);
	cColumnDesc = m_cColumnDesc;
	// release the properties on all column and make the first column not nullable
	ReleaseAllColumnPropSets(rgColumnDesc, cColumnDesc);
	SetProperty(&rgColumnDesc[0].rgPropertySets, &rgColumnDesc[0].cPropertySets,
			DBPROP_COL_NULLABLE, 
			VT_BOOL, (LPVOID)VARIANT_FALSE, 
			DBPROPOPTIONS_REQUIRED);

	m_pTable->MakeTableName(NULL);
	TableID.eKind			= DBKIND_NAME;
	TableID.uName.pwszName	= m_pTable->GetTableName();

	// create support for foreign key constraint
	TESTC_(ReferencedTable.CreateTable(0, 0), S_OK);
	ReferencedTable.AddInfoFromColumnsSchemaRowset(m_pITDWC, ReferencedTable.GetTableName());
	// make the referenced columns unique
	TESTC_(AddUniqueConstraint(&ReferencedTable, rgReferencedCol[0], (DBDEFERRABILITY)0), S_OK);

	// set a unique constraint on the second column
	consUnique.AddColumn(&rgColumnDesc[1].dbcid);

	// set a primary key on the first column of the table
	consPrimaryKey.AddColumn(&rgColumnDesc[0].dbcid);

	// set a simple foreign key constraint
	TESTC_(ReferencedTable.GetColInfo(1, col), S_OK);
	consForeignKey.AddColumn(col.GetColID());
	consForeignKey.AddForeignKeyColumn(&rgColumnDesc[0].dbcid);
	consForeignKey.SetReferencedTableID(&ReferencedTable.GetTableID());

	// add all constraint to the array
	ConsDescArray.AddConsDesc(consUnique);
	ConsDescArray.AddConsDesc(consForeignKey);
	ConsDescArray.AddConsDesc(consPrimaryKey);

	TESTC_(CreateAndCheckTableWithConstraints(m_pITDWC, NULL, &TableID, cColumnDesc, rgColumnDesc, 
		ConsDescArray, ConsDescArray, 
		IID_IRowset, 0, NULL, NULL, NULL), S_OK);
	
	TESTC_(CreateAndCheckTableWithConstraints(m_pITDWC, NULL, &TableID, cColumnDesc, rgColumnDesc, 
		ConsDescArray, ConsDescArray, 
		IID_IRowset, 0, NULL, NULL, NULL), DB_E_DUPLICATETABLEID);

CLEANUP:
	CHECK(DropTableAndCheck(&TableID), S_OK);
	CHECK(ReferencedTable.DropTable(), S_OK);
	ReleaseColumnDesc(rgColumnDesc, cColumnDesc);
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(30)
//*-----------------------------------------------------------------------
// @mfunc Same constraint name in 2 constraints => DB_E_DUPLICATECONSTRAINTID
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCCreateTableWithConstraints_Boundary::Variation_30()
{ 
	TBEGIN
	CTable			ReferencedTable(m_pThisTestModule->m_pIUnknown2, (LPWSTR)gwszModuleName);
	DBID			TableID;
	DBCOLUMNDESC	*rgColumnDesc	= NULL;
	DBORDINAL		cColumnDesc		= 0;
	CConsDescArray	ConsDescArray;
	CUniqueCons		consUnique;
	CPrimaryKeyCons	consPrimaryKey;
	CForeignKeyCons	consForeignKey(NULL, m_SupportedMatchType);
	DBORDINAL		rgReferencedCol[] = {1};
	CCol			col;

	DuplicateColumnDesc(m_rgColumnDesc, m_cColumnDesc, &rgColumnDesc);
	cColumnDesc = m_cColumnDesc;
	// release the properties on all column and make the first column not nullable
	ReleaseAllColumnPropSets(rgColumnDesc, cColumnDesc);
	SetProperty(&rgColumnDesc[0].rgPropertySets, &rgColumnDesc[0].cPropertySets,
			DBPROP_COL_NULLABLE, 
			VT_BOOL, (LPVOID)VARIANT_FALSE, 
			DBPROPOPTIONS_REQUIRED);

	m_pTable->MakeTableName(NULL);
	TableID.eKind			= DBKIND_NAME;
	TableID.uName.pwszName	= m_pTable->GetTableName();

	// create support for foreign key constraint
	TESTC_(ReferencedTable.CreateTable(0, 0), S_OK);
	ReferencedTable.AddInfoFromColumnsSchemaRowset(m_pITDWC, ReferencedTable.GetTableName());
	// make the referenced columns unique
	TESTC_(AddUniqueConstraint(&ReferencedTable, rgReferencedCol[0], (DBDEFERRABILITY)0), S_OK);

	// set a unique constraint on the second column
	consUnique.AddColumn(&rgColumnDesc[1].dbcid);

	// set a primary key on the first column of the table
	consPrimaryKey.AddColumn(&rgColumnDesc[0].dbcid);
	consPrimaryKey.SetConstraintName(consUnique.GetConstraintID()->uName.pwszName);

	// set a simple foreign key constraint
	TESTC_(ReferencedTable.GetColInfo(1, col), S_OK);
	consForeignKey.AddColumn(col.GetColID());
	consForeignKey.AddForeignKeyColumn(&rgColumnDesc[0].dbcid);
	consForeignKey.SetReferencedTableID(&ReferencedTable.GetTableID());

	// add all constraint to the array
	ConsDescArray.AddConsDesc(consUnique);
	ConsDescArray.AddConsDesc(consForeignKey);
	ConsDescArray.AddConsDesc(consPrimaryKey);

	TESTC_(CreateAndCheckTableWithConstraints(m_pITDWC, NULL, &TableID, cColumnDesc, rgColumnDesc, 
		ConsDescArray, ConsDescArray, 
		IID_IRowset, 0, NULL, NULL, NULL), DB_E_DUPLICATECONSTRAINTID);
	
CLEANUP:
	CHECK(ReferencedTable.DropTable(), S_OK);
	ReleaseColumnDesc(rgColumnDesc, cColumnDesc);
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(31)
//*-----------------------------------------------------------------------
// @mfunc NULL pConstraintID in 2 constraints => S_OK
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCCreateTableWithConstraints_Boundary::Variation_31()
{ 
	TBEGIN
	CTable			ReferencedTable(m_pThisTestModule->m_pIUnknown2, (LPWSTR)gwszModuleName);
	DBID			TableID;
	DBCOLUMNDESC	*rgColumnDesc	= NULL;
	DBORDINAL		cColumnDesc		= 0;
	CConsDescArray	ConsDescArray;
	CUniqueCons		consUnique;
	CPrimaryKeyCons	consPrimaryKey;
	CForeignKeyCons	consForeignKey(NULL, m_SupportedMatchType);
	DBORDINAL		rgReferencedCol[] = {1};
	CCol			col;

	DuplicateColumnDesc(m_rgColumnDesc, m_cColumnDesc, &rgColumnDesc);
	cColumnDesc = m_cColumnDesc;
	// release the properties on all column and make the first column not nullable
	ReleaseAllColumnPropSets(rgColumnDesc, cColumnDesc);
	SetProperty(&rgColumnDesc[0].rgPropertySets, &rgColumnDesc[0].cPropertySets,
			DBPROP_COL_NULLABLE, 
			VT_BOOL, (LPVOID)VARIANT_FALSE, 
			DBPROPOPTIONS_REQUIRED);

	m_pTable->MakeTableName(NULL);
	TableID.eKind			= DBKIND_NAME;
	TableID.uName.pwszName	= m_pTable->GetTableName();

	// create support for foreign key constraint
	TESTC_(ReferencedTable.CreateTable(0, 0), S_OK);
	ReferencedTable.AddInfoFromColumnsSchemaRowset(m_pITDWC, ReferencedTable.GetTableName());
	// make the referenced columns unique
	TESTC_(AddUniqueConstraint(&ReferencedTable, rgReferencedCol[0], (DBDEFERRABILITY)0), S_OK);

	// set a unique constraint on the second column
	consUnique.AddColumn(&rgColumnDesc[1].dbcid);
	ReleaseDBID(((DBCONSTRAINTDESC*)consUnique)->pConstraintID, TRUE);
	((DBCONSTRAINTDESC*)consUnique)->pConstraintID = NULL;

	// set a primary key on the first column of the table
	consPrimaryKey.AddColumn(&rgColumnDesc[0].dbcid);
	ReleaseDBID(((DBCONSTRAINTDESC*)consPrimaryKey)->pConstraintID);
	((DBCONSTRAINTDESC*)consPrimaryKey)->pConstraintID = NULL;

	// set a simple foreign key constraint
	TESTC_(ReferencedTable.GetColInfo(1, col), S_OK);
	consForeignKey.AddColumn(col.GetColID());
	consForeignKey.AddForeignKeyColumn(&rgColumnDesc[0].dbcid);
	consForeignKey.SetReferencedTableID(&ReferencedTable.GetTableID());

	// add all constraint to the array
	ConsDescArray.AddConsDesc(consUnique);
	ConsDescArray.AddConsDesc(consForeignKey);
	ConsDescArray.AddConsDesc(consPrimaryKey);

	TESTC_(CreateAndCheckTableWithConstraints(m_pITDWC, NULL, &TableID, cColumnDesc, rgColumnDesc, 
		ConsDescArray, ConsDescArray, 
		IID_IRowset, 0, NULL, NULL, NULL), S_OK);
	
CLEANUP:
	CHECK(DropTableAndCheck(&TableID), S_OK);
	CHECK(ReferencedTable.DropTable(), S_OK);
	ReleaseColumnDesc(rgColumnDesc, cColumnDesc);
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(32)
//*-----------------------------------------------------------------------
// @mfunc Try to create table with constraints, but table already exists => DB_E_DUPLICATEDTABLEID
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCCreateTableWithConstraints_Boundary::Variation_32()
{ 
	TBEGIN
	HRESULT			hr;
	CTable			ReferencedTable(m_pThisTestModule->m_pIUnknown2, (LPWSTR)gwszModuleName);
	DBID			TableID;
	DBCOLUMNDESC	*rgColumnDesc	= NULL;
	DBORDINAL		cColumnDesc		= 0;
	CConsDescArray	ConsDescArray;
	CUniqueCons		consUnique;
	CPrimaryKeyCons	consPrimaryKey;
	CForeignKeyCons	consForeignKey(NULL, m_SupportedMatchType);
	DBORDINAL		rgReferencedCol[] = {1};
	CCol			col;

	DuplicateColumnDesc(m_rgColumnDesc, m_cColumnDesc, &rgColumnDesc);
	cColumnDesc = m_cColumnDesc;
	// release the properties on all column and make the first column not nullable
	ReleaseAllColumnPropSets(rgColumnDesc, cColumnDesc);
	SetProperty(&rgColumnDesc[0].rgPropertySets, &rgColumnDesc[0].cPropertySets,
			DBPROP_COL_NULLABLE, 
			VT_BOOL, (LPVOID)VARIANT_FALSE, 
			DBPROPOPTIONS_REQUIRED);

	m_pTable->MakeTableName(NULL);
	TableID.eKind			= DBKIND_NAME;
	TableID.uName.pwszName	= m_pTable->GetTableName();

	// create support for foreign key constraint
	TESTC_(ReferencedTable.CreateTable(0, 0), S_OK);
	ReferencedTable.AddInfoFromColumnsSchemaRowset(m_pITDWC, ReferencedTable.GetTableName());
	// make the referenced columns unique
	TESTC_(AddUniqueConstraint(&ReferencedTable, rgReferencedCol[0], (DBDEFERRABILITY)0), S_OK);

	// set a unique constraint on the second column
	consUnique.AddColumn(&rgColumnDesc[1].dbcid);

	// set a primary key on the first column of the table
	consPrimaryKey.AddColumn(&rgColumnDesc[0].dbcid);

	// set a simple foreign key constraint
	TESTC_(ReferencedTable.GetColInfo(1, col), S_OK);
	consForeignKey.AddColumn(col.GetColID());
	consForeignKey.AddForeignKeyColumn(&rgColumnDesc[0].dbcid);
	consForeignKey.SetReferencedTableID(&ReferencedTable.GetTableID());

	// add all constraint to the array
	ConsDescArray.AddConsDesc(consUnique);
	ConsDescArray.AddConsDesc(consForeignKey);
	ConsDescArray.AddConsDesc(consPrimaryKey);

	TESTC_(CreateAndCheckTableWithConstraints(m_pITDWC, NULL, &TableID, cColumnDesc, rgColumnDesc, 
		ConsDescArray, ConsDescArray, 
		IID_IRowset, 0, NULL, NULL, NULL), S_OK);

	TESTC_(hr = CreateAndCheckTableWithConstraints(m_pITDWC, NULL, &TableID, cColumnDesc, rgColumnDesc, 
		ConsDescArray, ConsDescArray, 
		IID_IRowset, 0, NULL, NULL, NULL), DB_E_DUPLICATETABLEID);
	
CLEANUP:
	CHECK(DropTableAndCheck(&TableID), S_OK);
	CHECK(ReferencedTable.DropTable(), S_OK);
	ReleaseColumnDesc(rgColumnDesc, cColumnDesc);
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END


// {{ TCW_TERMINATE_METHOD
//*-----------------------------------------------------------------------
// @mfunc TestCase Termination Routine 
//
// @rdesc TEST_PASS or TEST_FAIL 
//
BOOL TCCreateTableWithConstraints_Boundary::Terminate()
{ 
	// TO DO:  Add your own code here 

// {{ TCW_TERM_BASECLASS_CHECK2
	return(TCITableDefinition::Terminate());
} 	// }}
// }} TCW_TERMINATE_METHOD_END
// }} TCW_TC_PROTOTYPE_END



// {{ TCW_TC_PROTOTYPE(TCDropConstraint)
//*-----------------------------------------------------------------------
//| Test Case:		TCDropConstraint - Testcase for ITableDefinitionWithConstraints::DropConstraint
//| Created:  	8/9/99
//*-----------------------------------------------------------------------

//*-----------------------------------------------------------------------
// @mfunc TestCase Initialization Routine
//
// @rdesc TRUE or FALSE
//
BOOL TCDropConstraint::Init()
{ 
	// {{ TCW_INIT_BASECLASS_CHECK
	if(TCITableDefinition::Init())
	// }}
	{ 
		if (m_pITDWC == NULL)
		{
			odtLog << "ITableDefinitionWithConstraints is not supported.\n";
			return TEST_SKIPPED;
		}
		return TRUE;
	} 
	return FALSE;
} 




// {{ TCW_VAR_PROTOTYPE(1)
//*-----------------------------------------------------------------------
// @mfunc pTableID is NULL => E_INVALIDARG
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCDropConstraint::Variation_1()
{ 
	TBEGIN
	CTable				Table(m_pThisTestModule->m_pIUnknown2, (LPWSTR)gwszModuleName);
	CUniqueCons			cons;
	CCol				col;

	TESTC_(Table.CreateTable(0, 0), S_OK);
	Table.AddInfoFromColumnsSchemaRowset(m_pITDWC, Table.GetTableName());

	// choose 1 column and create a unique constraint on them
	TESTC_(Table.GetColInfo(1, col), S_OK);

	// Add constraint
	cons.AddColumn(col.GetColID());
	TESTC_(AddConstraintAndCheck(m_pITDWC, &Table.GetTableID(), cons), S_OK);

	// drop the constraint 
	TESTC_(DropConstraintAndCheck(m_pITDWC, NULL, cons), E_INVALIDARG);

CLEANUP:
	Table.DropTable();
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(2)
//*-----------------------------------------------------------------------
// @mfunc pTableID.uName.pwszName is NULL => DB_E_BADTABLEID
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCDropConstraint::Variation_2()
{ 
	TBEGIN
	CTable				Table(m_pThisTestModule->m_pIUnknown2, (LPWSTR)gwszModuleName);
	CUniqueCons			cons;
	DBCONSTRAINTDESC	*pConsDesc = (DBCONSTRAINTDESC*)cons;
	CCol				col;
	DBID				TableID;

	TESTC_(Table.CreateTable(0, 0), S_OK);
	Table.AddInfoFromColumnsSchemaRowset(m_pITDWC, Table.GetTableName());

	// alloc memory for column array
	pConsDesc->cColumns = 1;
	SAFE_ALLOC(pConsDesc->rgColumnList, DBID, pConsDesc->cColumns);
	memset(pConsDesc->rgColumnList, 0, sizeof(pConsDesc->rgColumnList));

	// choose 1 column and create a unique constraint on them
	TESTC_(Table.GetColInfo(1, col), S_OK);
	DuplicateDBID(*col.GetColID(), pConsDesc->rgColumnList);

	TESTC_(AddConstraintAndCheck(m_pITDWC, &Table.GetTableID(), cons), S_OK);

	// drop the constraint 
	TableID.eKind			= DBKIND_NAME;
	TableID.uName.pwszName	= NULL;
	TEST2C_(DropConstraintAndCheck(m_pITDWC, &TableID, pConsDesc->pConstraintID), DB_E_BADTABLEID, DB_E_NOTABLE);

CLEANUP:
	Table.DropTable();
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(3)
//*-----------------------------------------------------------------------
// @mfunc Table name is empty => DB_E_BADTABLEID
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCDropConstraint::Variation_3()
{ 
	TBEGIN
	CTable				Table(m_pThisTestModule->m_pIUnknown2, (LPWSTR)gwszModuleName);
	CUniqueCons			cons;
	DBCONSTRAINTDESC	*pConsDesc = (DBCONSTRAINTDESC*)cons;
	CCol				col;
	DBID				TableID;

	TESTC_(Table.CreateTable(0, 0), S_OK);
	Table.AddInfoFromColumnsSchemaRowset(m_pITDWC, Table.GetTableName());

	// alloc memory for column array
	pConsDesc->cColumns = 1;
	SAFE_ALLOC(pConsDesc->rgColumnList, DBID, pConsDesc->cColumns);
	memset(pConsDesc->rgColumnList, 0, sizeof(pConsDesc->rgColumnList));

	// choose 1 column and create a unique constraint on them
	TESTC_(Table.GetColInfo(1, col), S_OK);
	DuplicateDBID(*col.GetColID(), pConsDesc->rgColumnList);

	TESTC_(AddConstraintAndCheck(m_pITDWC, &Table.GetTableID(), cons), S_OK);

	// drop the constraint 
	TableID.eKind			= DBKIND_NAME;
	TableID.uName.pwszName	= L"";
	TEST2C_(DropConstraintAndCheck(m_pITDWC, &TableID, pConsDesc->pConstraintID), 
		DB_E_BADTABLEID, DB_E_NOTABLE);

CLEANUP:
	Table.DropTable();
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(4)
//*-----------------------------------------------------------------------
// @mfunc Table name is not the one on which the column was created
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCDropConstraint::Variation_4()
{ 
	TBEGIN
	CTable				Table(m_pThisTestModule->m_pIUnknown2, (LPWSTR)gwszModuleName);
	CTable				Table2(m_pThisTestModule->m_pIUnknown2, (LPWSTR)gwszModuleName);
	CUniqueCons			cons;
	DBCONSTRAINTDESC	*pConsDesc = (DBCONSTRAINTDESC*)cons;
	CCol				col;
	HRESULT				hr;

	TESTC_(Table.CreateTable(0, 0), S_OK);
	Table.AddInfoFromColumnsSchemaRowset(m_pITDWC, Table.GetTableName());
	TESTC_(Table2.CreateTable(0, 0), S_OK);
	Table2.AddInfoFromColumnsSchemaRowset(m_pITDWC, Table2.GetTableName());

	// alloc memory for column array
	pConsDesc->cColumns = 1;
	SAFE_ALLOC(pConsDesc->rgColumnList, DBID, pConsDesc->cColumns);
	memset(pConsDesc->rgColumnList, 0, sizeof(pConsDesc->rgColumnList));

	// choose 1 column and create a unique constraint on them
	TESTC_(Table.GetColInfo(1, col), S_OK);
	DuplicateDBID(*col.GetColID(), pConsDesc->rgColumnList);

	TESTC_(AddConstraintAndCheck(m_pITDWC, &Table.GetTableID(), cons), S_OK);

	// drop the constraint 
	TEST2C_(hr = DropConstraintAndCheck(m_pITDWC, &Table2.GetTableID(), 
		pConsDesc->pConstraintID), S_OK, E_FAIL);

	TESTC_(DropConstraintAndCheck(m_pITDWC, &Table.GetTableID(), pConsDesc->pConstraintID), 
		(S_OK == hr)? DB_E_BADTABLEID: S_OK);

CLEANUP:
	Table.DropTable();
	Table2.DropTable();
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(5)
//*-----------------------------------------------------------------------
// @mfunc Inexistent table name => DB_E_NOTABLE
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCDropConstraint::Variation_5()
{ 
	TBEGIN
	CTable				Table(m_pThisTestModule->m_pIUnknown2, (LPWSTR)gwszModuleName);
	CTable				Table2(m_pThisTestModule->m_pIUnknown2, (LPWSTR)gwszModuleName);
	CUniqueCons			cons;
	DBCONSTRAINTDESC	*pConsDesc = (DBCONSTRAINTDESC*)cons;
	CCol				col;

	TESTC_(Table.CreateTable(0, 0), S_OK);
	Table.AddInfoFromColumnsSchemaRowset(m_pITDWC, Table.GetTableName());

	// alloc memory for column array
	pConsDesc->cColumns = 1;
	SAFE_ALLOC(pConsDesc->rgColumnList, DBID, pConsDesc->cColumns);
	memset(pConsDesc->rgColumnList, 0, sizeof(pConsDesc->rgColumnList));

	// choose 1 column and create a unique constraint on them
	TESTC_(Table.GetColInfo(1, col), S_OK);
	DuplicateDBID(*col.GetColID(), pConsDesc->rgColumnList);

	TESTC_(AddConstraintAndCheck(m_pITDWC, &Table.GetTableID(), cons), S_OK);

	// drop the constraint 
	TESTC_(Table2.MakeTableName(NULL), S_OK);

	TESTC_(DropConstraintAndCheck(m_pITDWC, &Table2.GetTableID(), pConsDesc->pConstraintID), DB_E_NOTABLE);

CLEANUP:
	Table.DropTable();
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END





// {{ TCW_VAR_PROTOTYPE(6)
//*-----------------------------------------------------------------------
// @mfunc Maximum table name => S_OK
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCDropConstraint::Variation_6()
{ 
	TBEGIN
	CTable			Table(m_pThisTestModule->m_pIUnknown2, (LPWSTR)gwszModuleName);
	CUniqueCons		cons;
	CCol			col;
	WCHAR			*pwszTableName = NULL;

	// create the base table with maximum name length
	Table.MakeTableName(NULL);
	pwszTableName = BuildValidName(m_cMaxTableName, Table.GetTableName());
	TESTC_(Table.CreateTable(0, 0, pwszTableName), S_OK);
	Table.AddInfoFromColumnsSchemaRowset(m_pITDWC, Table.GetTableName());

	// choose 1 column and create a unique constraint on them
	TESTC_(Table.GetColInfo(1, col), S_OK);

	// Add constraint
	cons.AddColumn(col.GetColID());
	TESTC_(AddConstraintAndCheck(m_pITDWC, &Table.GetTableID(), cons), S_OK);

	// drop the constraint 
	TESTC_(DropConstraintAndCheck(m_pITDWC, &Table.GetTableID(), 
		cons.GetConstraintID()), S_OK);

CLEANUP:
	Table.DropTable();
	SAFE_FREE(pwszTableName);
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(7)
//*-----------------------------------------------------------------------
// @mfunc Invalid characters in table's name => DB_E_BADTABLEID
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCDropConstraint::Variation_7()
{ 
	TBEGIN
	CTable			Table(m_pThisTestModule->m_pIUnknown2, (LPWSTR)gwszModuleName);
	CUniqueCons		cons;
	CCol			col;
	size_t			m, n;
	DBID			TableID;

	// create the base table 
	TESTC_(Table.CreateTable(0), S_OK);
	Table.AddInfoFromColumnsSchemaRowset(m_pITDWC, Table.GetTableName());

	// choose 1 column and create a unique constraint on them
	TESTC_(Table.GetColInfo(1, col), S_OK);

	// Add constraint
	cons.AddColumn(col.GetColID());
	TESTC_(AddConstraintAndCheck(m_pITDWC, &Table.GetTableID(), cons), S_OK);

	// set an invalid table name
	m = min(m_cMaxColName, n=5+wcslen(Table.GetTableName()));
	TableID.eKind			= DBKIND_NAME;
	TableID.uName.pwszName	= BuildInvalidName(m, Table.GetTableName(), m_pwszInvalidColChars);

	// drop the constraint 
	TEST2C_(DropConstraintAndCheck(m_pITDWC, &TableID, cons.GetConstraintID()), DB_E_BADTABLEID, DB_E_NOTABLE);

CLEANUP:
	Table.DropTable();
	ReleaseDBID(&TableID, FALSE);
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(8)
//*-----------------------------------------------------------------------
// @mfunc pConstraintID is NUL => E_INVALIDARG
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCDropConstraint::Variation_8()
{ 
	TBEGIN
	CTable				Table(m_pThisTestModule->m_pIUnknown2, (LPWSTR)gwszModuleName);
	CUniqueCons			cons;
	CCol				col;

	TESTC_(Table.CreateTable(0, 0), S_OK);
	Table.AddInfoFromColumnsSchemaRowset(m_pITDWC, Table.GetTableName());

	// choose 1 column and create a unique constraint on them
	TESTC_(Table.GetColInfo(1, col), S_OK);

	// Add constraint
	cons.AddColumn(col.GetColID());
	TESTC_(AddConstraintAndCheck(m_pITDWC, &Table.GetTableID(), cons), S_OK);

	// drop the constraint and recreate it
	TESTC_(DropConstraintAndCheck(m_pITDWC, &Table.GetTableID(), NULL), E_INVALIDARG);

CLEANUP:
	Table.DropTable();
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(9)
//*-----------------------------------------------------------------------
// @mfunc *pConstraintID is DB_NULLID => DB_E_NOCONSTRAINT
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCDropConstraint::Variation_9()
{ 
	TBEGIN
	CTable				Table(m_pThisTestModule->m_pIUnknown2, (LPWSTR)gwszModuleName);
	CUniqueCons			cons;
	CCol				col;

	TESTC_(Table.CreateTable(0, 0), S_OK);
	Table.AddInfoFromColumnsSchemaRowset(m_pITDWC, Table.GetTableName());

	// choose 1 column and create a unique constraint on them
	TESTC_(Table.GetColInfo(1, col), S_OK);

	// Add constraint
	cons.AddColumn(col.GetColID());
	TESTC_(AddConstraintAndCheck(m_pITDWC, &Table.GetTableID(), cons), S_OK);

	// drop the constraint 
	cons.SetConstraintID((DBID*)&DB_NULLID);
	TESTC_(DropConstraintAndCheck(m_pITDWC, &Table.GetTableID(), cons), DB_E_NOCONSTRAINT);

CLEANUP:
	Table.DropTable();
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(10)
//*-----------------------------------------------------------------------
// @mfunc Invalid DBKIND in the constraint name => DB_E_NOCONSTRAINT
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCDropConstraint::Variation_10()
{ 
	TBEGIN
	CTable				Table(m_pThisTestModule->m_pIUnknown2, (LPWSTR)gwszModuleName);
	CUniqueCons			cons;
	CCol				col;

	TESTC_(Table.CreateTable(0, 0), S_OK);
	Table.AddInfoFromColumnsSchemaRowset(m_pITDWC, Table.GetTableName());

	// choose 1 column and create a unique constraint on them
	TESTC_(Table.GetColInfo(1, col), S_OK);

	// Add constraint
	cons.AddColumn(col.GetColID());
	TESTC_(AddConstraintAndCheck(m_pITDWC, &Table.GetTableID(), cons), S_OK);

	// drop the constraint 
	ReleaseDBID(((DBCONSTRAINTDESC*)cons)->pConstraintID, FALSE);
	((DBCONSTRAINTDESC*)cons)->pConstraintID->eKind = 0xa0;

	TESTC_(DropConstraintAndCheck(m_pITDWC, &Table.GetTableID(), cons), DB_E_NOCONSTRAINT);

CLEANUP:
	((DBCONSTRAINTDESC*)cons)->pConstraintID->eKind = DBKIND_NAME;
	Table.DropTable();
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(11)
//*-----------------------------------------------------------------------
// @mfunc NULL constraint name => DB_E_NOCONSTRAINT
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCDropConstraint::Variation_11()
{ 
	TBEGIN
	CTable				Table(m_pThisTestModule->m_pIUnknown2, (LPWSTR)gwszModuleName);
	CUniqueCons			cons;
	CCol				col;

	TESTC_(Table.CreateTable(0, 0), S_OK);
	Table.AddInfoFromColumnsSchemaRowset(m_pITDWC, Table.GetTableName());

	// choose 1 column and create a unique constraint on them
	TESTC_(Table.GetColInfo(1, col), S_OK);

	// Add constraint
	cons.AddColumn(col.GetColID());
	TESTC_(AddConstraintAndCheck(m_pITDWC, &Table.GetTableID(), cons), S_OK);

	// drop the constraint 
	cons.SetConstraintName(NULL);

	TESTC_(DropConstraintAndCheck(m_pITDWC, &Table.GetTableID(), cons), DB_E_NOCONSTRAINT);

CLEANUP:
	Table.DropTable();
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(12)
//*-----------------------------------------------------------------------
// @mfunc Constraint name is empty string => DB_E_NOCONSTRAINT
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCDropConstraint::Variation_12()
{ 
	TBEGIN
	CTable				Table(m_pThisTestModule->m_pIUnknown2, (LPWSTR)gwszModuleName);
	CUniqueCons			cons;
	CCol				col;

	TESTC_(Table.CreateTable(0, 0), S_OK);
	Table.AddInfoFromColumnsSchemaRowset(m_pITDWC, Table.GetTableName());

	// choose 1 column and create a unique constraint on them
	TESTC_(Table.GetColInfo(1, col), S_OK);

	// Add constraint
	cons.AddColumn(col.GetColID());
	TESTC_(AddConstraintAndCheck(m_pITDWC, &Table.GetTableID(), cons), S_OK);

	// drop the constraint 
	cons.SetConstraintName(L"");

	TESTC_(DropConstraintAndCheck(m_pITDWC, &Table.GetTableID(), cons), DB_E_NOCONSTRAINT);

CLEANUP:
	Table.DropTable();
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(13)
//*-----------------------------------------------------------------------
// @mfunc Inexistent constraint name => DB_E_NOCONSTRAINT
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCDropConstraint::Variation_13()
{ 
	TBEGIN
	CTable				Table(m_pThisTestModule->m_pIUnknown2, (LPWSTR)gwszModuleName);
	CUniqueCons			cons;
	CCol				col;

	TESTC_(Table.CreateTable(0, 0), S_OK);
	Table.AddInfoFromColumnsSchemaRowset(m_pITDWC, Table.GetTableName());

	// choose 1 column and create a unique constraint on them
	TESTC_(Table.GetColInfo(1, col), S_OK);

	// Add constraint
	cons.AddColumn(col.GetColID());
	TESTC_(AddConstraintAndCheck(m_pITDWC, &Table.GetTableID(), cons), S_OK);

	// drop the constraint 
	cons.MakeConstraintName();
	TESTC_(DropConstraintAndCheck(m_pITDWC, &Table.GetTableID(), cons), DB_E_NOCONSTRAINT);

CLEANUP:
	Table.DropTable();
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(14)
//*-----------------------------------------------------------------------
// @mfunc Drop a constraint twice
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCDropConstraint::Variation_14()
{ 
	TBEGIN
	CTable				Table(m_pThisTestModule->m_pIUnknown2, (LPWSTR)gwszModuleName);
	CUniqueCons			cons;
	CCol				col;

	TESTC_(Table.CreateTable(0, 0), S_OK);
	Table.AddInfoFromColumnsSchemaRowset(m_pITDWC, Table.GetTableName());

	// choose a column and create a unique constraint on it
	TESTC_(Table.GetColInfo(1, col), S_OK);

	// Add constraint
	cons.AddColumn(col.GetColID());
	TESTC_(AddConstraintAndCheck(m_pITDWC, &Table.GetTableID(), cons), S_OK);

	// drop the constraint 
	TESTC_(DropConstraintAndCheck(m_pITDWC, &Table.GetTableID(), cons), S_OK);
	TESTC_(DropConstraintAndCheck(m_pITDWC, &Table.GetTableID(), cons), DB_E_NOCONSTRAINT);

CLEANUP:
	Table.DropTable();
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(15)
//*-----------------------------------------------------------------------
// @mfunc Drop a unique constraint
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCDropConstraint::Variation_15()
{ 
	TBEGIN
	CTable				Table(m_pThisTestModule->m_pIUnknown2, (LPWSTR)gwszModuleName);
	CUniqueCons			cons;
	CCol				col;

	TESTC_(Table.CreateTable(0, 0), S_OK);
	Table.AddInfoFromColumnsSchemaRowset(m_pITDWC, Table.GetTableName());

	// choose a column and create a unique constraint on it
	TESTC_(Table.GetColInfo(1, col), S_OK);

	// Add constraint
	cons.AddColumn(col.GetColID());
	TESTC_(AddConstraintAndCheck(m_pITDWC, &Table.GetTableID(), cons), S_OK);

	// drop the constraint 
	TESTC_(DropConstraintAndCheck(m_pITDWC, &Table.GetTableID(), cons), S_OK);

CLEANUP:
	Table.DropTable();
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(16)
//*-----------------------------------------------------------------------
// @mfunc Drop a primary key constraint
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCDropConstraint::Variation_16()
{ 
	TBEGIN
	CTable				Table(m_pThisTestModule->m_pIUnknown2, (LPWSTR)gwszModuleName);
	CPrimaryKeyCons		cons;
	CCol				col;

	TESTC_(CreateTableWithNoNullableColumns(&Table, 0), S_OK);

	// choose a column and create a primary key constraint on it
	TESTC_(Table.GetColInfo(1, col), S_OK);

	// Add constraint
	cons.AddColumn(col.GetColID());
	TESTC_(AddConstraintAndCheck(m_pITDWC, &Table.GetTableID(), cons), S_OK);

	// drop the constraint 
	TESTC_(DropConstraintAndCheck(m_pITDWC, &Table.GetTableID(), cons), S_OK);

CLEANUP:
	Table.DropTable();
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(17)
//*-----------------------------------------------------------------------
// @mfunc Drop a foreign key constraint
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCDropConstraint::Variation_17()
{ 
	TBEGIN
	CTable				BaseTable(m_pITDWC, (LPWSTR)gwszModuleName);
	CTable				ReferencedTable(m_pITDWC, (LPWSTR)gwszModuleName);
	CForeignKeyCons		cons(NULL, m_SupportedMatchType);
	CCol				col;

	TESTC_(BaseTable.CreateTable(0, 0), S_OK);
	BaseTable.AddInfoFromColumnsSchemaRowset(m_pITDWC, BaseTable.GetTableName());
	
	TESTC_(ReferencedTable.CreateTable(0, 0), S_OK);
	ReferencedTable.AddInfoFromColumnsSchemaRowset(m_pITDWC, ReferencedTable.GetTableName());
	TESTC_(AddUniqueConstraint(&ReferencedTable, 1), S_OK);

	// choose 1 column and create a unique constraint on them
	TESTC_(BaseTable.GetColInfo(1, col), S_OK);
	cons.AddForeignKeyColumn(col.GetColID());

	TESTC_(ReferencedTable.GetColInfo(1, col), S_OK);
	cons.AddColumn(col.GetColID());

	cons.SetReferencedTableID(&ReferencedTable.GetTableID());

	TESTC_(AddConstraintAndCheck(m_pITDWC, &BaseTable.GetTableID(), cons), S_OK);

	// drop the constraint 
	TESTC_(DropConstraintAndCheck(m_pITDWC, &BaseTable.GetTableID(), cons), S_OK);

CLEANUP:
	CHECK(BaseTable.DropTable(), S_OK);
	CHECK(ReferencedTable.DropTable(), S_OK);
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(18)
//*-----------------------------------------------------------------------
// @mfunc Drop a check constraint
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCDropConstraint::Variation_18()
{ 
	TBEGIN
	CTable		Table(m_pThisTestModule->m_pIUnknown2, (LPWSTR)gwszModuleName);
	CCheckCons	cons;
	CCol		col;
	WCHAR		*pwszConstraintText = NULL;
	WCHAR		wszText[] = L" IS NOT NULL";

	TESTC_(CreateTableWithNoNullableColumns(&Table, 0), S_OK);

	// choose a column and create a primary key constraint on it
	TESTC_(Table.GetColInfo(1, col), S_OK);

	// Add constraint
	// build constraint text
	TESTC_PROVIDER(DBKIND_NAME == col.GetColID()->eKind);
	SAFE_ALLOC(pwszConstraintText, WCHAR, 1 + wcslen(col.GetColID()->uName.pwszName) + wcslen(wszText));
	wcscpy(pwszConstraintText, col.GetColID()->uName.pwszName);
	wcscat(pwszConstraintText, wszText);
	cons.SetConstraintText(pwszConstraintText);
	TESTC_(AddConstraintAndCheck(m_pITDWC, &Table.GetTableID(), cons), S_OK);

	// drop the constraint 
	TESTC_(DropConstraintAndCheck(m_pITDWC, &Table.GetTableID(), cons), S_OK);

CLEANUP:
	Table.DropTable();
	SAFE_FREE(pwszConstraintText);
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(19)
//*-----------------------------------------------------------------------
// @mfunc Create several constraints, drop a single constraint
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCDropConstraint::Variation_19()
{ 
	TBEGIN
	CTable			ReferencedTable(m_pThisTestModule->m_pIUnknown2, (LPWSTR)gwszModuleName);
	DBID			TableID;
	DBCOLUMNDESC	*rgColumnDesc	= NULL;
	DBORDINAL		cColumnDesc		= 0;
	CConsDescArray	ConsDescArray;
	CUniqueCons		consUnique;
	CPrimaryKeyCons	consPrimaryKey;
	CForeignKeyCons	consForeignKey(NULL, m_SupportedMatchType);
	DBORDINAL		rgReferencedCol[] = {1};
	CCol			col;

	DuplicateColumnDesc(m_rgColumnDesc, m_cColumnDesc, &rgColumnDesc);
	cColumnDesc = m_cColumnDesc;
	// release the properties on all column and make the first column not nullable
	ReleaseAllColumnPropSets(rgColumnDesc, cColumnDesc);
	SetProperty(&rgColumnDesc[0].rgPropertySets, &rgColumnDesc[0].cPropertySets,
			DBPROP_COL_NULLABLE, 
			VT_BOOL, (LPVOID)VARIANT_FALSE, 
			DBPROPOPTIONS_REQUIRED);

	m_pTable->MakeTableName(NULL);
	TableID.eKind			= DBKIND_NAME;
	TableID.uName.pwszName	= m_pTable->GetTableName();

	// create support for foreign key constraint
	TESTC_(ReferencedTable.CreateTable(0, 0), S_OK);
	ReferencedTable.AddInfoFromColumnsSchemaRowset(m_pITDWC, ReferencedTable.GetTableName());

	// make the referenced columns unique
	TESTC_(AddUniqueConstraint(&ReferencedTable, rgReferencedCol[0], (DBDEFERRABILITY)0), S_OK);

	// set a unique constraint on the second column
	consUnique.AddColumn(&rgColumnDesc[1].dbcid);

	// set a primary key on the first column of the table
	consPrimaryKey.AddColumn(&rgColumnDesc[0].dbcid);

	// set a simple foreign key constraint
	TESTC_(ReferencedTable.GetColInfo(1, col), S_OK);
	consForeignKey.AddColumn(col.GetColID());
	consForeignKey.AddForeignKeyColumn(&rgColumnDesc[0].dbcid);
	consForeignKey.SetReferencedTableID(&ReferencedTable.GetTableID());

	// add all constraint to the array
	ConsDescArray.AddConsDesc(consUnique);
	ConsDescArray.AddConsDesc(consForeignKey);
	ConsDescArray.AddConsDesc(consPrimaryKey);

	TESTC_(CreateAndCheckTableWithConstraints(m_pITDWC, NULL, &TableID, cColumnDesc, rgColumnDesc, 
		ConsDescArray, ConsDescArray, 
		IID_IRowset, 0, NULL, NULL, NULL), S_OK);

	CHECK(DropConstraintAndCheck(m_pITDWC, &TableID, consForeignKey),	S_OK);
	CHECK(DropConstraintAndCheck(m_pITDWC, &TableID, consUnique),	S_OK);
	CHECK(DropConstraintAndCheck(m_pITDWC, &TableID, consPrimaryKey),	S_OK);
	
CLEANUP:
	CHECK(DropTableAndCheck(&TableID), S_OK);
	CHECK(ReferencedTable.DropTable(), S_OK);
	ReleaseColumnDesc(rgColumnDesc, cColumnDesc);
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(20)
//*-----------------------------------------------------------------------
// @mfunc Drop a unique constraint in the referenced table, after the foreign key constraint was added
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCDropConstraint::Variation_20()
{ 
	TBEGIN
	CTable				BaseTable(m_pITDWC, (LPWSTR)gwszModuleName);
	CTable				ReferencedTable(m_pITDWC, (LPWSTR)gwszModuleName);
	CForeignKeyCons		cons(NULL, m_SupportedMatchType);
	CUniqueCons			consUnique;
	CUniqueCons			consUnique1;
	CCol				col;

	TESTC_(BaseTable.CreateTable(0, 0), S_OK);
	BaseTable.AddInfoFromColumnsSchemaRowset(m_pITDWC, BaseTable.GetTableName());

	TESTC_(ReferencedTable.CreateTable(0, 0), S_OK);
	ReferencedTable.AddInfoFromColumnsSchemaRowset(m_pITDWC, ReferencedTable.GetTableName());

	consUnique.SetConstraint(&ReferencedTable, 1);
	TESTC_(AddConstraintAndCheck(m_pITDWC, &ReferencedTable.GetTableID(), consUnique), S_OK);

	consUnique1.SetConstraint(&ReferencedTable, 2);
	TESTC_(AddConstraintAndCheck(m_pITDWC, &ReferencedTable.GetTableID(), consUnique1), S_OK);

	// choose 1 column and create a unique constraint on them
	TESTC_(BaseTable.GetColInfo(1, col), S_OK);
	cons.AddForeignKeyColumn(col.GetColID());

	TESTC_(ReferencedTable.GetColInfo(1, col), S_OK);
	cons.AddColumn(col.GetColID());

	cons.SetReferencedTableID(&ReferencedTable.GetTableID());

	TESTC_(AddConstraintAndCheck(m_pITDWC, &BaseTable.GetTableID(), cons), S_OK);

	// drop the unique constraints on the referenced table
	CHECK(DropConstraintAndCheck(m_pITDWC, &ReferencedTable.GetTableID(), consUnique), 
		DB_E_DROPRESTRICTED);
	CHECK(DropConstraintAndCheck(m_pITDWC, &ReferencedTable.GetTableID(), consUnique1), 
		S_OK);

	// drop the foreign key constraint on the base table
	CHECK(DropConstraintAndCheck(m_pITDWC, &BaseTable.GetTableID(), cons), S_OK);

	// drop the unique constraint on the referenced table
	CHECK(DropConstraintAndCheck(m_pITDWC, &ReferencedTable.GetTableID(), consUnique), 
		S_OK);

CLEANUP:
	CHECK(BaseTable.DropTable(), S_OK);
	CHECK(ReferencedTable.DropTable(), S_OK);
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(21)
//*-----------------------------------------------------------------------
// @mfunc Try to drop a unique constraint while a rowset is opened on the table => DB_E_TABLEINUSE
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCDropConstraint::Variation_21()
{ 
	TBEGIN
	CTable				Table(m_pThisTestModule->m_pIUnknown2, (LPWSTR)gwszModuleName);
	CUniqueCons			cons;
	CCol				col;
	IRowsetChange		*pIRowsetChange	= NULL;
	HRESULT				hr;

	TESTC_(Table.CreateTable(0, 0), S_OK);
	Table.AddInfoFromColumnsSchemaRowset(m_pITDWC, Table.GetTableName());

	// choose a column and create a unique constraint on it
	TESTC_(Table.GetColInfo(3, col), S_OK);

	// Add constraint
	cons.AddColumn(col.GetColID());
	TESTC_(AddConstraintAndCheck(m_pITDWC, &Table.GetTableID(), cons), S_OK);

	// open a rowset on the table 
	CHECK(Table.Insert(7), S_OK);
	CHECK(Table.Insert(7), DB_E_INTEGRITYVIOLATION);
	TESTC_(hr = m_pIOpenRowset->OpenRowset(NULL, &Table.GetTableID(), NULL, 
		IID_IRowsetChange, 0, NULL, (IUnknown**)&pIRowsetChange), S_OK);

	// drop the constraint 
	TEST2C_(hr = DropConstraintAndCheck(m_pITDWC, &Table.GetTableID(), cons), 
		S_OK, DB_E_TABLEINUSE);

	if (S_OK == hr)
	{
		odtLog << "Constraint was dropped\n";
		CHECK(Table.Insert(7), S_OK);
	}
	else
		CHECK(Table.Insert(7), DB_E_INTEGRITYVIOLATION);


CLEANUP:
	SAFE_RELEASE(pIRowsetChange);
	Table.DropTable();
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(22)
//*-----------------------------------------------------------------------
// @mfunc *pTableID is DB_NULLID => DB_E_BADTABLEID
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCDropConstraint::Variation_22()
{ 
	TBEGIN
	CTable				Table(m_pThisTestModule->m_pIUnknown2, (LPWSTR)gwszModuleName);
	CUniqueCons			cons;
	CCol				col;

	TESTC_(Table.CreateTable(0, 0), S_OK);
	Table.AddInfoFromColumnsSchemaRowset(m_pITDWC, Table.GetTableName());

	// choose 1 column and create a unique constraint on them
	TESTC_(Table.GetColInfo(1, col), S_OK);

	// Add constraint
	cons.AddColumn(col.GetColID());
	TESTC_(AddConstraintAndCheck(m_pITDWC, &Table.GetTableID(), cons), S_OK);

	// drop the constraint 
	TEST2C_(DropConstraintAndCheck(m_pITDWC, (DBID*)&DB_NULLID, cons), DB_E_BADTABLEID, DB_E_NOTABLE);

CLEANUP:
	Table.DropTable();
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(23)
//*-----------------------------------------------------------------------
// @mfunc Invalid DBKIND in pTableID => DB_E_BADTABLEID
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCDropConstraint::Variation_23()
{ 
	TBEGIN
	CTable				Table(m_pThisTestModule->m_pIUnknown2, (LPWSTR)gwszModuleName);
	CUniqueCons			cons;
	CCol				col;
	DBID				TableID;

	TESTC_(Table.CreateTable(0, 0), S_OK);
	Table.AddInfoFromColumnsSchemaRowset(m_pITDWC, Table.GetTableName());

	// choose 1 column and create a unique constraint on them
	TESTC_(Table.GetColInfo(1, col), S_OK);

	// Add constraint
	cons.AddColumn(col.GetColID());
	TESTC_(AddConstraintAndCheck(m_pITDWC, &Table.GetTableID(), cons), S_OK);

	// drop the constraint 
	TableID.eKind = 0x44;
	TEST2C_(DropConstraintAndCheck(m_pITDWC, &TableID, cons), DB_E_BADTABLEID, DB_E_NOTABLE);

CLEANUP:
	Table.DropTable();
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(24)
//*-----------------------------------------------------------------------
// @mfunc Try to drop a check constraint while a rowset is opened on the table => DB_E_TABLEINUSE
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCDropConstraint::Variation_24()
{ 
	TBEGIN
	CTable		Table(m_pThisTestModule->m_pIUnknown2, (LPWSTR)gwszModuleName);
	CCheckCons	cons;
	CCol		col;
	WCHAR		*pwszConstraintText = NULL;
	WCHAR		wszText[] = L" IS NOT NULL";
	IRowsetChange		*pIRowsetChange	= NULL;

	TESTC_(CreateTableWithNoNullableColumns(&Table, 0), S_OK);

	// choose a column and create a primary key constraint on it
	TESTC_(Table.GetColInfo(1, col), S_OK);

	// Add constraint
	// build constraint text
	TESTC_PROVIDER(DBKIND_NAME == col.GetColID()->eKind);
	SAFE_ALLOC(pwszConstraintText, WCHAR, 1 + wcslen(col.GetColID()->uName.pwszName) + wcslen(wszText));
	wcscpy(pwszConstraintText, col.GetColID()->uName.pwszName);
	wcscat(pwszConstraintText, wszText);
	cons.SetConstraintText(pwszConstraintText);
	TESTC_(AddConstraintAndCheck(m_pITDWC, &Table.GetTableID(), cons), S_OK);

	TESTC_(m_pIOpenRowset->OpenRowset(NULL, &Table.GetTableID(), NULL, 
		IID_IRowsetChange, 0, NULL, (IUnknown**)&pIRowsetChange), S_OK);

	// drop the constraint 
	TEST2C_(DropConstraintAndCheck(m_pITDWC, &Table.GetTableID(), cons), S_OK, DB_E_TABLEINUSE);

CLEANUP:
	SAFE_RELEASE(pIRowsetChange);
	Table.DropTable();
	SAFE_FREE(pwszConstraintText);
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(25)
//*-----------------------------------------------------------------------
// @mfunc Try to drop a pk constraint while a rowset is opened on the table => DB_E_TABLEINUSE
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCDropConstraint::Variation_25()
{ 
	TBEGIN
	CTable				Table(m_pThisTestModule->m_pIUnknown2, (LPWSTR)gwszModuleName);
	CPrimaryKeyCons		cons;
	CCol				col;
	IRowsetChange		*pIRowsetChange	= NULL;

	TESTC_(CreateTableWithNoNullableColumns(&Table, 0), S_OK);

	// choose a column and create a primary key constraint on it
	TESTC_(Table.GetColInfo(1, col), S_OK);

	// Add constraint
	cons.AddColumn(col.GetColID());
	TESTC_(AddConstraintAndCheck(m_pITDWC, &Table.GetTableID(), cons), S_OK);

	TESTC_(m_pIOpenRowset->OpenRowset(NULL, &Table.GetTableID(), NULL, 
		IID_IRowsetChange, 0, NULL, (IUnknown**)&pIRowsetChange), S_OK);

	// drop the constraint 
	TEST2C_(DropConstraintAndCheck(m_pITDWC, &Table.GetTableID(), cons), S_OK, DB_E_TABLEINUSE);

CLEANUP:
	SAFE_RELEASE(pIRowsetChange);
	Table.DropTable();
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(26)
//*-----------------------------------------------------------------------
// @mfunc Try to drop a fk constraint while a rowset is opened on the table => DB_E_TABLEINUSE
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCDropConstraint::Variation_26()
{ 
	TBEGIN
	CTable				BaseTable(m_pITDWC, (LPWSTR)gwszModuleName);
	CTable				ReferencedTable(m_pITDWC, (LPWSTR)gwszModuleName);
	CForeignKeyCons		cons(NULL, m_SupportedMatchType);
	CCol				col;
	IRowsetChange		*pIRowsetChange	= NULL;

	TESTC_(BaseTable.CreateTable(0, 0), S_OK);
	BaseTable.AddInfoFromColumnsSchemaRowset(m_pITDWC, BaseTable.GetTableName());
	
	TESTC_(ReferencedTable.CreateTable(0, 0), S_OK);
	ReferencedTable.AddInfoFromColumnsSchemaRowset(m_pITDWC, ReferencedTable.GetTableName());

	TESTC_(AddUniqueConstraint(&ReferencedTable, 1), S_OK);

	// choose 1 column and create a unique constraint on them
	TESTC_(BaseTable.GetColInfo(1, col), S_OK);
	cons.AddForeignKeyColumn(col.GetColID());

	TESTC_(ReferencedTable.GetColInfo(1, col), S_OK);
	cons.AddColumn(col.GetColID());

	cons.SetReferencedTableID(&ReferencedTable.GetTableID());

	TESTC_(AddConstraintAndCheck(m_pITDWC, &BaseTable.GetTableID(), cons), S_OK);

	TESTC_(m_pIOpenRowset->OpenRowset(NULL, &BaseTable.GetTableID(), NULL, 
		IID_IRowsetChange, 0, NULL, (IUnknown**)&pIRowsetChange), S_OK);

	// drop the constraint 
	TEST2C_(DropConstraintAndCheck(m_pITDWC, &BaseTable.GetTableID(), cons), S_OK, DB_E_TABLEINUSE);

CLEANUP:
	SAFE_RELEASE(pIRowsetChange);
	CHECK(BaseTable.DropTable(), S_OK);
	CHECK(ReferencedTable.DropTable(), S_OK);
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(27)
//*-----------------------------------------------------------------------
// @mfunc Both pTableID and pConstraintID are NULL => E_INVALIDARG
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCDropConstraint::Variation_27()
{ 
	TBEGIN
	CTable				BaseTable(m_pITDWC, (LPWSTR)gwszModuleName);
	CUniqueCons			cons;
	CCol				col;
	IRowsetChange		*pIRowsetChange	= NULL;

	TESTC_(BaseTable.CreateTable(0, 0), S_OK);
	BaseTable.AddInfoFromColumnsSchemaRowset(m_pITDWC, BaseTable.GetTableName());

	// choose 1 column and create a unique constraint on them
	TESTC_(BaseTable.GetColInfo(1, col), S_OK);
	// Add constraint
	cons.AddColumn(col.GetColID());

	TESTC_(AddConstraintAndCheck(m_pITDWC, &BaseTable.GetTableID(), cons), S_OK);

	TESTC_(m_pIOpenRowset->OpenRowset(NULL, &BaseTable.GetTableID(), NULL, 
		IID_IRowsetChange, 0, NULL, (IUnknown**)&pIRowsetChange), S_OK);

	// drop the constraint 
	TESTC_(DropConstraintAndCheck(m_pITDWC, NULL, NULL), E_INVALIDARG);

CLEANUP:
	SAFE_RELEASE(pIRowsetChange);
	CHECK(BaseTable.DropTable(), S_OK);
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(28)
//*-----------------------------------------------------------------------
// @mfunc Abort retain
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCDropConstraint::Variation_28()
{ 
	CDropConsTxnAdapter	TxnAdapter(this);
	CTransactionLocal	TxnLocal;

	return TxnLocal.DoTransactionTest(m_pITDWC, &TxnAdapter,
		TRUE,		// DDL
		TRUE,		// Abort
		TRUE		// Retaining
		);
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(29)
//*-----------------------------------------------------------------------
// @mfunc Abort non retain
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCDropConstraint::Variation_29()
{ 
	CDropConsTxnAdapter	TxnAdapter(this);
	CTransactionLocal	TxnLocal;

	return TxnLocal.DoTransactionTest(m_pITDWC, &TxnAdapter,
		TRUE,		// DDL
		TRUE,		// Abort
		FALSE		// Non Retaining
		);
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(30)
//*-----------------------------------------------------------------------
// @mfunc Commit retain
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCDropConstraint::Variation_30()
{ 
	CDropConsTxnAdapter	TxnAdapter(this);
	CTransactionLocal	TxnLocal;

	return TxnLocal.DoTransactionTest(m_pITDWC, &TxnAdapter,
		TRUE,		// DDL
		FALSE,		// Commit
		TRUE		// Retaining
		);
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(31)
//*-----------------------------------------------------------------------
// @mfunc Commit non retain
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCDropConstraint::Variation_31()
{ 
	CDropConsTxnAdapter	TxnAdapter(this);
	CTransactionLocal	TxnLocal;

	return TxnLocal.DoTransactionTest(m_pITDWC, &TxnAdapter,
		TRUE,		// DDL
		FALSE,		// Commit
		FALSE		// Non Retaining
		);
} 
// }} TCW_VAR_PROTOTYPE_END


// {{ TCW_TERMINATE_METHOD
//*-----------------------------------------------------------------------
// @mfunc TestCase Termination Routine 
//
// @rdesc TEST_PASS or TEST_FAIL 
//
BOOL TCDropConstraint::Terminate()
{ 
	// TO DO:  Add your own code here 

// {{ TCW_TERM_BASECLASS_CHECK2
	return(TCITableDefinition::Terminate());
} 	// }}
// }} TCW_TERMINATE_METHOD_END
// }} TCW_TC_PROTOTYPE_END



// {{ TCW_TC_PROTOTYPE(TCAddConstraint_Multithreading)
//*-----------------------------------------------------------------------
//| Test Case:		TCAddConstraint_Multithreading - Testcase for ITableDefinitionWithConstraints::AddConstraint used in multithreaded calls
//| Created:  	9/14/99
//*-----------------------------------------------------------------------

//*-----------------------------------------------------------------------
// @mfunc TestCase Initialization Routine
//
// @rdesc TRUE or FALSE
//
BOOL TCAddConstraint_Multithreading::Init()
{ 
	// {{ TCW_INIT_BASECLASS_CHECK
	if(TCITableDefinition::Init())
	// }}
	{ 
		if (m_pITDWC == NULL)
		{
			odtLog << "ITableDefinitionWithConstraints is not supported.\n";
			return TEST_SKIPPED;
		}
		return TRUE;
	} 
	return FALSE;
} 




//---------------------------------------------------------------------
//
// @cmember Thread funtion for TCAddConstraint_Multithreading
//---------------------------------------------------------------------
unsigned TCAddConstraint_Multithreading::MyThreadProc(ULONG i)
{
	HRESULT			hr;

	if (i>= nThreads)
		return 0;

	Sleep(0); // switch the context

  	hr = m_pITDWC->AddConstraint(m_prgTableID[i], &m_rgConstraintDesc[i]);
	Sleep(0); // switch the context

	m_rgResult[i] = hr;
	return 1;
} //TCAddConstraint_Multithreading::MyThreadProc




// {{ TCW_VAR_PROTOTYPE(1)
//*-----------------------------------------------------------------------
// @mfunc Each thread creates a different constraint
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCAddConstraint_Multithreading::Variation_1()
{
	TBEGIN
	DBORDINAL		cThreads = nThreads;
	CConsDesc		*pConsDesc = NULL;
	CTable			ReferencedTable(m_pITDWC, (LPWSTR)gwszModuleName);
	CTable			BaseTable(m_pITDWC, (LPWSTR)gwszModuleName);

	unsigned		rgIDThread[nThreads];
	HANDLE			hrgThread[nThreads];
	CInParam		rgThreadParam[nThreads];
	ULONG			i;
	
	DBORDINAL		rgCol[] = {1};
	HRESULT			rgValidHRes[]	= {	S_OK,
										E_FAIL,
										E_INVALIDARG,
										DB_E_DUPLICATECONSTRAINTID,
										DB_E_BADCONSTRAINTID,
										DB_E_BADCONSTRAINTTYPE,
										DB_E_BADUPDATEDELETERULE,
										DB_E_BADMATCHTYPE,
										DB_E_BADDEFERRABILITY,
										DB_E_BADCONSTRAINTFORM,
										DB_E_NOCOLUMN,
										DB_E_NOTABLE,
										DB_E_TABLEINUSE,
										DB_SEC_E_PERMISSIONDENIED,
										XACT_E_XTIONEXISTS,
                                        DB_E_SCHEMAVIOLATION
									}; 
	ULONG			cValidHRes = NUMELEM(rgValidHRes);
	CConstraints	Constraints(m_pITDWC);

	TESTC_(CreateTableWithNoNullableColumns(&BaseTable, 0), S_OK);
	TESTC_(ReferencedTable.CreateTable(0), S_OK);
	ReferencedTable.AddInfoFromColumnsSchemaRowset(m_pITDWC, ReferencedTable.GetTableName());
	TESTC_(AddUniqueConstraint(&ReferencedTable, 1), S_OK);

	SAFE_ALLOC(m_prgTableID, DBID*, nThreads);
	SAFE_ALLOC(m_rgConstraintDesc, DBCONSTRAINTDESC, nThreads);
	memset(m_rgConstraintDesc, 0, nThreads * sizeof(DBCONSTRAINTDESC));

	for (i=0; i< nThreads; i++)
	{
		m_rgResult[i] = -1;
		m_prgTableID[i]	= &BaseTable.GetTableIDRef();
		if (0 == i)
		{
			pConsDesc = new CPrimaryKeyCons(m_rgConstraintDesc+i);
			TESTC_(((CPrimaryKeyCons*)pConsDesc)->SetConstraint(&BaseTable, 1), S_OK);
		}
		else if (i%2)
		{
			pConsDesc = new CUniqueCons(m_rgConstraintDesc+i);
			TESTC_(((CUniqueCons*)pConsDesc)->SetConstraint(&BaseTable, 1), S_OK);
		}
		else
		{
			pConsDesc = new CForeignKeyCons(m_rgConstraintDesc+i);
			TESTC_(((CForeignKeyCons*)pConsDesc)->SetConstraint(&BaseTable, 1, rgCol, &ReferencedTable, 1, rgCol, m_SupportedMatchType), S_OK);
		}

		pConsDesc->MakeConstraintName();
		
		rgThreadParam[i].pObject	= this;
		rgThreadParam[i].i			= i;
	}
	
	// start the threads
	for (i=0; i<nThreads; i++)
	{
		hrgThread[i] = (HANDLE)_beginthreadex(NULL, 0, ThreadProc,
							(void*)&rgThreadParam[i],
							0, 
							&rgIDThread[i]);		// input param
		TESTC(0 != hrgThread[i]);
	}

	WaitForMultipleObjects(nThreads, (CONST HANDLE*)hrgThread, TRUE, 1000);
	Sleep(1000);
	for (i=0; i< nThreads; i++)
		CloseHandle(hrgThread[i]);

	for (i=0; i<nThreads; i++)
	{	
		if (!CHECK(m_rgResult[i], S_OK))
		{
			if (	m_rgConstraintDesc[i].pConstraintID
				&&	DBKIND_NAME == m_rgConstraintDesc[i].pConstraintID->eKind
				&&	m_rgConstraintDesc[i].pConstraintID->uName.pwszName)
				odtLog << "Constraint " << m_rgConstraintDesc[i].pConstraintID->uName.pwszName << " failed to be added\n";
			else
				odtLog << "Constraint no " << i << " failed to be added\n";

			COMPARE(CheckResult(m_rgResult[i], cValidHRes, rgValidHRes), TRUE);
		}
		else
		{
			// get all the constraints associated with the table
			if (	m_prgTableID[i] 
				&&	DBKIND_NAME == m_prgTableID[i]->eKind 
				&&	CHECK(Constraints.GetConstraints(NULL, NULL, m_prgTableID[i]->uName.pwszName, NULL, NULL, NULL), S_OK))
			{
				CHECK(Constraints.CheckIncludedConstraints(1, &m_rgConstraintDesc[i]), S_OK);
			}
		}
	}

CLEANUP:
	BaseTable.DropTable();
	ReferencedTable.DropTable();
	SAFE_FREE(m_prgTableID);
	CHECK(FreeConstraintDesc(&cThreads, &m_rgConstraintDesc, TRUE), S_OK);
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(2)
//*-----------------------------------------------------------------------
// @mfunc Some of the threads try to create the same constraint name
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCAddConstraint_Multithreading::Variation_2()
{ 
	TBEGIN
	DBORDINAL		cThreads = nThreads;
	CConsDesc		*pConsDesc = NULL;
	CTable			ReferencedTable(m_pITDWC, (LPWSTR)gwszModuleName);
	CTable			BaseTable(m_pITDWC, (LPWSTR)gwszModuleName);

	unsigned		rgIDThread[nThreads];
	HANDLE			hrgThread[nThreads];
	CInParam		rgThreadParam[nThreads];
	ULONG			i;

	const ULONG		cSameName	= 5;
	DBORDINAL		cDuplicates	= 0;

	DBORDINAL		rgCol[] = {1};
	HRESULT			rgValidHRes[]	= {	S_OK,
										E_FAIL,
										E_INVALIDARG,
										DB_E_DUPLICATECONSTRAINTID,
										DB_E_BADCONSTRAINTID,
										DB_E_BADCONSTRAINTTYPE,
										DB_E_BADUPDATEDELETERULE,
										DB_E_BADMATCHTYPE,
										DB_E_BADDEFERRABILITY,
										DB_E_BADCONSTRAINTFORM,
										DB_E_NOCOLUMN,
										DB_E_NOTABLE,
										DB_E_TABLEINUSE,
										DB_SEC_E_PERMISSIONDENIED,
										XACT_E_XTIONEXISTS,
							            DB_E_SCHEMAVIOLATION
                                		}; 
	ULONG			cValidHRes = NUMELEM(rgValidHRes);
	CConstraints	Constraints(m_pITDWC);

	TESTC_PROVIDER(cSameName <= nThreads);

	TESTC_(CreateTableWithNoNullableColumns(&BaseTable, 0), S_OK);
	TESTC_(ReferencedTable.CreateTable(0), S_OK);
	ReferencedTable.AddInfoFromColumnsSchemaRowset(m_pITDWC, ReferencedTable.GetTableName());
	TESTC_(AddUniqueConstraint(&ReferencedTable, 1), S_OK);

	SAFE_ALLOC(m_prgTableID, DBID*, nThreads);
	SAFE_ALLOC(m_rgConstraintDesc, DBCONSTRAINTDESC, nThreads);
	memset(m_rgConstraintDesc, 0, nThreads * sizeof(DBCONSTRAINTDESC));
	for (i=0; i< nThreads; i++)
	{
		m_rgResult[i] = -1;
		m_prgTableID[i]	= &BaseTable.GetTableIDRef();

		if (0 == i)
		{
			pConsDesc = new CPrimaryKeyCons(m_rgConstraintDesc+i);
			TESTC_(((CPrimaryKeyCons*)pConsDesc)->SetConstraint(&BaseTable, 1), S_OK);
		}
		else if (i%2)
		{
			pConsDesc = new CUniqueCons(m_rgConstraintDesc+i);
			TESTC_(((CUniqueCons*)pConsDesc)->SetConstraint(&BaseTable, 1), S_OK);
		}
		else
		{
			pConsDesc = new CForeignKeyCons(m_rgConstraintDesc+i);
			TESTC_(((CForeignKeyCons*)pConsDesc)->SetConstraint(&BaseTable, 1, rgCol, &ReferencedTable, 1, rgCol, m_SupportedMatchType), S_OK);
		}

		if (0 == i || i >= cSameName)
			pConsDesc->MakeConstraintName();
		else
			// several constraints have the same name
			pConsDesc->SetConstraintID(m_rgConstraintDesc[0].pConstraintID);
		
		rgThreadParam[i].pObject	= this;
		rgThreadParam[i].i			= i;
	}
	
	// start threads
	for (i=0; i<nThreads; i++)
	{
		hrgThread[i] = (HANDLE)_beginthreadex(NULL, 0, ThreadProc,
							(void*)&rgThreadParam[i],
							0, 
							&rgIDThread[i]);		// input param
		TESTC(0 != hrgThread[i]);
	}

	WaitForMultipleObjects(nThreads, (CONST HANDLE*)hrgThread, TRUE, 1000);
	Sleep(1000);
	for (i=0; i< nThreads; i++)
		CloseHandle(hrgThread[i]);

	for (i=0; i<nThreads; i++)
	{	
		if (S_OK != m_rgResult[i])
		{
			COMPARE(CompareDBID(*m_rgConstraintDesc[0].pConstraintID, 
					*m_rgConstraintDesc[i].pConstraintID), TRUE);
			
			if (CHECK(m_rgResult[i], DB_E_DUPLICATECONSTRAINTID))
				cDuplicates++;

			if (	m_rgConstraintDesc[i].pConstraintID
				&&	DBKIND_NAME == m_rgConstraintDesc[i].pConstraintID->eKind
				&&	m_rgConstraintDesc[i].pConstraintID->uName.pwszName)
				odtLog << "Constraint " << m_rgConstraintDesc[i].pConstraintID->uName.pwszName << " failed to be added\n";
			else
				odtLog << "Constraint no " << i << " failed to be added\n";
		}
		else
		{
			// get all the constraints associated with the table
			if (	m_prgTableID[i] 
				&&	DBKIND_NAME == m_prgTableID[i]->eKind 
				&&	CHECK(Constraints.GetConstraints(NULL, NULL, m_prgTableID[i]->uName.pwszName, NULL, NULL, NULL), S_OK))
			{
				CHECK(Constraints.CheckIncludedConstraints(1, &m_rgConstraintDesc[i]), S_OK);
			}
		}
	}

	// exactly cSameName - 1 ops should have failed
	TESTC(cSameName - 1 == cDuplicates);

CLEANUP:
	BaseTable.DropTable();
	ReferencedTable.DropTable();
	SAFE_FREE(m_prgTableID);
	CHECK(FreeConstraintDesc(&cThreads, &m_rgConstraintDesc, TRUE), S_OK);
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(3)
//*-----------------------------------------------------------------------
// @mfunc Unique constraints with disjoint columns
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCAddConstraint_Multithreading::Variation_3()
{ 
	TBEGIN
	ULONG			cThreads = nThreads;
	CConsDesc		*pConsDesc = NULL;
	CTable			ReferencedTable(m_pITDWC, (LPWSTR)gwszModuleName);
	CTable			BaseTable(m_pITDWC, (LPWSTR)gwszModuleName);

	unsigned		rgIDThread[nThreads];
	HANDLE			hrgThread[nThreads];
	CInParam		rgThreadParam[nThreads];
	ULONG			i;
	DBORDINAL		iCol;
	DBORDINAL		cConsDescs = 0;

	HRESULT			rgValidHRes[]	= {	S_OK,
										E_FAIL,
										E_INVALIDARG,
										DB_E_DUPLICATECONSTRAINTID,
										DB_E_BADCONSTRAINTID,
										DB_E_BADCONSTRAINTTYPE,
										DB_E_BADUPDATEDELETERULE,
										DB_E_BADMATCHTYPE,
										DB_E_BADDEFERRABILITY,
										DB_E_BADCONSTRAINTFORM,
										DB_E_NOCOLUMN,
										DB_E_NOTABLE,
										DB_E_TABLEINUSE,
										DB_SEC_E_PERMISSIONDENIED,
										XACT_E_XTIONEXISTS,
							            DB_E_SCHEMAVIOLATION
									}; 
	ULONG			cValidHRes = NUMELEM(rgValidHRes);
	CConstraints	Constraints(m_pITDWC);

	TESTC_(CreateTableWithNoNullableColumns(&BaseTable, 0), S_OK);
	TESTC_PROVIDER(nThreads <= BaseTable.CountColumnsOnTable());
	BaseTable.AddInfoFromColumnsSchemaRowset(m_pITDWC, BaseTable.GetTableName());

	SAFE_ALLOC(m_prgTableID, DBID*, nThreads);
	SAFE_ALLOC(m_rgConstraintDesc, DBCONSTRAINTDESC, nThreads);
	memset(m_rgConstraintDesc, 0, nThreads * sizeof(DBCONSTRAINTDESC));
	for (cThreads=0, iCol=1; iCol <= BaseTable.CountColumnsOnTable() && cThreads < nThreads; iCol++)
	{
		CCol	col;

		TESTC_(BaseTable.GetColInfo(iCol, col), S_OK);

		// Generally, setting unique constraints on BLOBs fail
		// Note: col.GetColumnSize returns length for string data types and we need size in bytes
		//			so multiply ColumnSize by 2 for WSTR

		if (col.GetIsLong() ||
			(col.GetIsFixedLength() && (col.GetColumnSize() * (col.GetProviderType()==DBTYPE_WSTR ? 2:1) > cMaxColLengthPerCons)))
			continue;
		
		m_rgResult[cThreads] = -1;
		m_prgTableID[cThreads]	= &BaseTable.GetTableIDRef();

		pConsDesc = new CUniqueCons(m_rgConstraintDesc+cThreads);
		
		TESTC_(((CUniqueCons*)pConsDesc)->SetConstraint(&BaseTable, iCol), S_OK);
		pConsDesc->MakeConstraintName();
		
		rgThreadParam[cThreads].pObject	= this;
		rgThreadParam[cThreads].i		= cThreads;
		cThreads++;
	}
	cConsDescs = cThreads;
	
	// start threads
	for (i=0; i<cThreads; i++)
	{
		hrgThread[i] = (HANDLE)_beginthreadex(NULL, 0, ThreadProc,
							(void*)&rgThreadParam[i],
							0, 
							&rgIDThread[i]);		// input param
		TESTC(0 != hrgThread[i]);
	}

	WaitForMultipleObjects(cThreads, (CONST HANDLE*)hrgThread, TRUE, 1000);
	Sleep(1000);
	for (i=0; i< cThreads; i++)
		CloseHandle(hrgThread[i]);

	for (i=0; i< cThreads; i++)
	{	
		if (CHECK(m_rgResult[i], S_OK))
		{
			// get all the constraints associated with the table
			if (	m_prgTableID[i] 
				&&	DBKIND_NAME == m_prgTableID[i]->eKind 
				&&	CHECK(Constraints.GetConstraints(NULL, NULL, m_prgTableID[i]->uName.pwszName, NULL, NULL, NULL), S_OK))
			{
				CHECK(Constraints.CheckIncludedConstraints(1, &m_rgConstraintDesc[i]), S_OK);
			}
		}
	}


CLEANUP:
	BaseTable.DropTable();
	SAFE_FREE(m_prgTableID);
	CHECK(FreeConstraintDesc(&cConsDescs, &m_rgConstraintDesc, TRUE), S_OK);
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(4)
//*-----------------------------------------------------------------------
// @mfunc Unique constraints with overlapping columns
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCAddConstraint_Multithreading::Variation_4()
{ 
	TBEGIN
	DBORDINAL		cThreads = nThreads;
	CConsDesc		*pConsDesc = NULL;
	CTable			ReferencedTable(m_pITDWC, (LPWSTR)gwszModuleName);
	CTable			BaseTable(m_pITDWC, (LPWSTR)gwszModuleName);

	unsigned		rgIDThread[nThreads];
	HANDLE			hrgThread[nThreads];
	CInParam		rgThreadParam[nThreads];
	ULONG			i;

	HRESULT			rgValidHRes[]	= {	S_OK,
										E_FAIL,
										E_INVALIDARG,
										DB_E_DUPLICATECONSTRAINTID,
										DB_E_BADCONSTRAINTID,
										DB_E_BADCONSTRAINTTYPE,
										DB_E_BADUPDATEDELETERULE,
										DB_E_BADMATCHTYPE,
										DB_E_BADDEFERRABILITY,
										DB_E_BADCONSTRAINTFORM,
										DB_E_NOCOLUMN,
										DB_E_NOTABLE,
										DB_E_TABLEINUSE,
										DB_SEC_E_PERMISSIONDENIED,
										XACT_E_XTIONEXISTS,
							            DB_E_SCHEMAVIOLATION
									}; 
	ULONG			cValidHRes = NUMELEM(rgValidHRes);
	CConstraints	Constraints(m_pITDWC);

	TESTC_(CreateTableWithNoNullableColumns(&BaseTable, 0), S_OK);
	TESTC_PROVIDER(nThreads <= BaseTable.CountColumnsOnTable());

	SAFE_ALLOC(m_prgTableID, DBID*, nThreads);
	SAFE_ALLOC(m_rgConstraintDesc, DBCONSTRAINTDESC, nThreads);
	memset(m_rgConstraintDesc, 0, nThreads * sizeof(DBCONSTRAINTDESC));
	for (i=0; i< nThreads; i++)
	{
		m_rgResult[i] = -1;
		m_prgTableID[i]	= &BaseTable.GetTableIDRef();

		pConsDesc = new CUniqueCons(m_rgConstraintDesc+i);
		TESTC_(((CUniqueCons*)pConsDesc)->SetConstraint(&BaseTable, 1), S_OK);
		pConsDesc->MakeConstraintName();
		
		rgThreadParam[i].pObject	= this;
		rgThreadParam[i].i			= i;
	}
	
	// start threads
	for (i=0; i<nThreads; i++)
	{
		hrgThread[i] = (HANDLE)_beginthreadex(NULL, 0, ThreadProc,
							(void*)&rgThreadParam[i],
							0, 
							&rgIDThread[i]);		// input param
		TESTC(0 != hrgThread[i]);
	}

	WaitForMultipleObjects(nThreads, (CONST HANDLE*)hrgThread, TRUE, 1000);
	Sleep(1000);
	for (i=0; i< nThreads; i++)
		CloseHandle(hrgThread[i]);

	for (i=0; i<nThreads; i++)
	{	
		if (CHECK(m_rgResult[i], S_OK))
		{
			// get all the constraints associated with the table
			if (	m_prgTableID[i] 
				&&	DBKIND_NAME == m_prgTableID[i]->eKind 
				&&	CHECK(Constraints.GetConstraints(NULL, NULL, m_prgTableID[i]->uName.pwszName, NULL, NULL, NULL), S_OK))
			{
				CHECK(Constraints.CheckIncludedConstraints(1, &m_rgConstraintDesc[i]), S_OK);
			}
		}
	}


CLEANUP:
	BaseTable.DropTable();
	SAFE_FREE(m_prgTableID);
	CHECK(FreeConstraintDesc(&cThreads, &m_rgConstraintDesc, TRUE), S_OK);
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END





// {{ TCW_VAR_PROTOTYPE(5)
//*-----------------------------------------------------------------------
// @mfunc All constraint IDs are generated by the provider
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCAddConstraint_Multithreading::Variation_5()
{ 
	TBEGIN
	DBORDINAL		cThreads = nThreads;
	CConsDesc		*pConsDesc = NULL;
	CTable			ReferencedTable(m_pITDWC, (LPWSTR)gwszModuleName);
	CTable			BaseTable(m_pITDWC, (LPWSTR)gwszModuleName);

	unsigned		rgIDThread[nThreads];
	HANDLE			hrgThread[nThreads];
	CInParam		rgThreadParam[nThreads];
	ULONG			i;
	
	DBORDINAL		rgCol[] = {1};
	HRESULT			rgValidHRes[]	= {	S_OK,
										E_FAIL,
										E_INVALIDARG,
										DB_E_DUPLICATECONSTRAINTID,
										DB_E_BADCONSTRAINTID,
										DB_E_BADCONSTRAINTTYPE,
										DB_E_BADUPDATEDELETERULE,
										DB_E_BADMATCHTYPE,
										DB_E_BADDEFERRABILITY,
										DB_E_BADCONSTRAINTFORM,
										DB_E_NOCOLUMN,
										DB_E_NOTABLE,
										DB_E_TABLEINUSE,
										DB_SEC_E_PERMISSIONDENIED,
										XACT_E_XTIONEXISTS,
							            DB_E_SCHEMAVIOLATION
									}; 
	ULONG			cValidHRes = NUMELEM(rgValidHRes);
	CConstraints	Constraints(m_pITDWC);

	TESTC_(CreateTableWithNoNullableColumns(&BaseTable, 0), S_OK);
	TESTC_(ReferencedTable.CreateTable(0), S_OK);
	ReferencedTable.AddInfoFromColumnsSchemaRowset(m_pITDWC, ReferencedTable.GetTableName());
	TESTC_(AddUniqueConstraint(&ReferencedTable, 1), S_OK);

	SAFE_ALLOC(m_prgTableID, DBID*, nThreads);
	SAFE_ALLOC(m_rgConstraintDesc, DBCONSTRAINTDESC, nThreads);
	memset(m_rgConstraintDesc, 0, nThreads * sizeof(DBCONSTRAINTDESC));
	for (i=0; i< nThreads; i++)
	{
		m_rgResult[i] = -1;
		m_prgTableID[i]	= &BaseTable.GetTableIDRef();

		if (0 == i)
		{
			pConsDesc = new CPrimaryKeyCons(m_rgConstraintDesc+i);
			TESTC_(((CPrimaryKeyCons*)pConsDesc)->SetConstraint(&BaseTable, 1), S_OK);
		}
		else if (i%2)
		{
			pConsDesc = new CUniqueCons(m_rgConstraintDesc+i);
			TESTC_(((CUniqueCons*)pConsDesc)->SetConstraint(&BaseTable, 1), S_OK);
		}
		else
		{
			pConsDesc = new CForeignKeyCons(m_rgConstraintDesc+i);
			TESTC_(((CForeignKeyCons*)pConsDesc)->SetConstraint(&BaseTable, 1, rgCol, &ReferencedTable, 1, rgCol, m_SupportedMatchType), S_OK);
		}

		pConsDesc->SetConstraintID(NULL);
		
		rgThreadParam[i].pObject	= this;
		rgThreadParam[i].i			= i;
	}
	
	// start the threads
	for (i=0; i<nThreads; i++)
	{
		hrgThread[i] = (HANDLE)_beginthreadex(NULL, 0, ThreadProc,
							(void*)&rgThreadParam[i],
							0, 
							&rgIDThread[i]);		// input param
		TESTC(0 != hrgThread[i]);
	}

	WaitForMultipleObjects(nThreads, (CONST HANDLE*)hrgThread, TRUE, 1000);
	Sleep(1000);
	for (i=0; i< nThreads; i++)
		CloseHandle(hrgThread[i]);

	for (i=0; i<nThreads; i++)
	{	
		if (CHECK(m_rgResult[i], S_OK))
		{
			// get all the constraints associated with the table
			if (	m_prgTableID[i] 
				&&	DBKIND_NAME == m_prgTableID[i]->eKind 
				&&	CHECK(Constraints.GetConstraints(NULL, NULL, m_prgTableID[i]->uName.pwszName, NULL, NULL, NULL), S_OK)
				&&	m_rgConstraintDesc[i].pConstraintID
				)
			{
				CHECK(Constraints.CheckIncludedConstraints(1, &m_rgConstraintDesc[i]), S_OK);
			}
		}
	}

	COMPARE(Constraints.GetConstrNo(), nThreads);

CLEANUP:
	BaseTable.DropTable();
	ReferencedTable.DropTable();
	SAFE_FREE(m_prgTableID);
	CHECK(FreeConstraintDesc(&cThreads, &m_rgConstraintDesc, TRUE), S_OK);
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END


// {{ TCW_TERMINATE_METHOD
//*-----------------------------------------------------------------------
// @mfunc TestCase Termination Routine 
//
// @rdesc TEST_PASS or TEST_FAIL 
//
BOOL TCAddConstraint_Multithreading::Terminate()
{ 
	// TO DO:  Add your own code here 

// {{ TCW_TERM_BASECLASS_CHECK2
	return(TCITableDefinition::Terminate());
} 	// }}
// }} TCW_TERMINATE_METHOD_END
// }} TCW_TC_PROTOTYPE_END


// {{ TCW_TC_PROTOTYPE(TCDropConstraint_Multithreading)
//*-----------------------------------------------------------------------
//| Test Case:		TCDropConstraint_Multithreading - Multithreading test case for ITableDefinitionWithConstraints::DropConstraints
//| Created:  	9/16/99
//*-----------------------------------------------------------------------

//*-----------------------------------------------------------------------
// @mfunc TestCase Initialization Routine
//
// @rdesc TRUE or FALSE
//
BOOL TCDropConstraint_Multithreading::Init()
{ 
	// {{ TCW_INIT_BASECLASS_CHECK
	if(TCITableDefinition::Init())
	// }}
	{ 
		if (m_pITDWC == NULL)
		{
			odtLog << "ITableDefinitionWithConstraints is not supported.\n";
			return TEST_SKIPPED;
		}
		return TRUE;
	} 
	return FALSE;
} 




//---------------------------------------------------------------------
//
// @cmember Thread funtion for TCDropConstraint_Multithreading
//---------------------------------------------------------------------
unsigned TCDropConstraint_Multithreading::MyThreadProc(ULONG i)
{
	HRESULT			hr;

	if (i>= nThreads)
		return 0;

	Sleep(0); // switch the context

  	hr = m_pITDWC->DropConstraint(m_prgTableID[i], m_prgConstraintID[i]);
	Sleep(0); // switch the context

	m_rgResult[i] = hr;
	return 1;
} //TCDropConstraint_Multithreading::MyThreadProc




// {{ TCW_VAR_PROTOTYPE(1)
//*-----------------------------------------------------------------------
// @mfunc Each thread drops a different constraint => all S_OK
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCDropConstraint_Multithreading::Variation_1()
{ 
	TBEGIN
	DBORDINAL			cThreads = nThreads;
	CConsDesc			*pConsDesc = NULL;
	CTable				ReferencedTable(m_pITDWC, (LPWSTR)gwszModuleName);
	CTable				BaseTable(m_pITDWC, (LPWSTR)gwszModuleName);

	unsigned			rgIDThread[nThreads];
	HANDLE				hrgThread[nThreads];
	CInParam			rgThreadParam[nThreads];
	ULONG				i;
	DBCONSTRAINTDESC	*rgConstraintDesc = NULL;
	DBORDINAL			rgCol[] = {1};
	HRESULT				rgValidHRes[]	= {	S_OK,
											E_FAIL,
											E_INVALIDARG,
											DB_E_NOCONSTRAINT,
											DB_E_BADTABLEID,
											DB_E_DROPRESTRICTED,
											DB_E_NOTABLE,
											DB_E_TABLEINUSE,
											DB_SEC_E_PERMISSIONDENIED,
											XACT_E_XTIONEXISTS,
    							            DB_E_SCHEMAVIOLATION
									}; 
	ULONG				cValidHRes = NUMELEM(rgValidHRes);
	CConstraints		Constraints(m_pITDWC);

	TESTC_(CreateTableWithNoNullableColumns(&BaseTable, 0), S_OK);
	TESTC_(ReferencedTable.CreateTable(0), S_OK);
	ReferencedTable.AddInfoFromColumnsSchemaRowset(m_pITDWC, ReferencedTable.GetTableName());
	TESTC_(AddUniqueConstraint(&ReferencedTable, 1), S_OK);

	SAFE_ALLOC(m_prgTableID, DBID*, nThreads);
	SAFE_ALLOC(rgConstraintDesc, DBCONSTRAINTDESC, nThreads);
	SAFE_ALLOC(m_prgConstraintID, DBID*, nThreads);
	memset(rgConstraintDesc, 0, nThreads * sizeof(DBCONSTRAINTDESC));
	for (i=0; i< nThreads; i++)
	{
		m_rgResult[i] = -1;
		m_prgTableID[i]	= &BaseTable.GetTableIDRef();

		// create a constraint
		if (0 == i)
		{
			pConsDesc = new CPrimaryKeyCons(rgConstraintDesc+i);
			TESTC_(((CPrimaryKeyCons*)pConsDesc)->SetConstraint(&BaseTable, 1), S_OK);
		}
		else if (i%2)
		{
			pConsDesc = new CUniqueCons(rgConstraintDesc+i);
			TESTC_(((CUniqueCons*)pConsDesc)->SetConstraint(&BaseTable, 1), S_OK);
		}
		else
		{
			pConsDesc = new CForeignKeyCons(rgConstraintDesc+i);
			TESTC_(((CForeignKeyCons*)pConsDesc)->SetConstraint(&BaseTable, 1, rgCol, &ReferencedTable, 1, rgCol, m_SupportedMatchType), S_OK);
		}

		pConsDesc->MakeConstraintName();
		TESTC_(m_pITDWC->AddConstraint(m_prgTableID[i], &rgConstraintDesc[i]), S_OK);

		m_prgConstraintID[i] = rgConstraintDesc[i].pConstraintID;

		rgThreadParam[i].pObject	= this;
		rgThreadParam[i].i			= i;
	}
	
	// start the threads
	for (i=0; i<nThreads; i++)
	{
		hrgThread[i] = (HANDLE)_beginthreadex(NULL, 0, ThreadProc,
							(void*)&rgThreadParam[i],
							0, 
							&rgIDThread[i]);		// input param
		TESTC(0 != hrgThread[i]);
	}

	WaitForMultipleObjects(nThreads, (CONST HANDLE*)hrgThread, TRUE, 1000);
	Sleep(1000);
	for (i=0; i< nThreads; i++)
		CloseHandle(hrgThread[i]);

	for (i=0; i<nThreads; i++)
	{	
		if (!CHECK(m_rgResult[i], S_OK))
		{
			if (	rgConstraintDesc[i].pConstraintID
				&&	DBKIND_NAME == rgConstraintDesc[i].pConstraintID->eKind
				&&	rgConstraintDesc[i].pConstraintID->uName.pwszName)
				odtLog << "Constraint " << rgConstraintDesc[i].pConstraintID->uName.pwszName << " failed to be added\n";
			else
				odtLog << "Constraint no " << i << " failed to be dropped\n";

			COMPARE(CheckResult(m_rgResult[i], cValidHRes, rgValidHRes), TRUE);
		}
		else
		{
			// get all the constraints associated with the table
			if (	m_prgTableID[i] 
				&&	DBKIND_NAME == m_prgTableID[i]->eKind 
				&&	CHECK(Constraints.GetConstraints(NULL, NULL, m_prgTableID[i]->uName.pwszName, NULL, NULL, NULL), S_OK))
			{
				COMPARE(NULL == Constraints[m_prgConstraintID[i]], TRUE);
			}
		}
	}

CLEANUP:
	BaseTable.DropTable();
	ReferencedTable.DropTable();
	SAFE_FREE(m_prgTableID);
	CHECK(FreeConstraintDesc(&cThreads, &rgConstraintDesc, TRUE), S_OK);
	SAFE_FREE(m_prgConstraintID);
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(2)
//*-----------------------------------------------------------------------
// @mfunc Some threads try to drop the same constraint => S_OK and DB_E_NOCONSTRAINT
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCDropConstraint_Multithreading::Variation_2()
{ 
	TBEGIN
	DBORDINAL			cThreads = nThreads;
	CConsDesc			*pConsDesc = NULL;
	CTable				ReferencedTable(m_pITDWC, (LPWSTR)gwszModuleName);
	CTable				BaseTable(m_pITDWC, (LPWSTR)gwszModuleName);

	unsigned			rgIDThread[nThreads];
	HANDLE				hrgThread[nThreads];
	CInParam			rgThreadParam[nThreads];
	ULONG				i;
	DBCONSTRAINTDESC	*rgConstraintDesc = NULL;
	DBORDINAL			rgCol[] = {1};
	HRESULT				rgValidHRes[]	= {	S_OK,
											E_FAIL,
											E_INVALIDARG,
											DB_E_NOCONSTRAINT,
											DB_E_BADTABLEID,
											DB_E_DROPRESTRICTED,
											DB_E_NOTABLE,
											DB_E_TABLEINUSE,
											DB_SEC_E_PERMISSIONDENIED,
											XACT_E_XTIONEXISTS,
    							            DB_E_SCHEMAVIOLATION
									}; 
	ULONG				cValidHRes = NUMELEM(rgValidHRes);
	CConstraints		Constraints(m_pITDWC);

	DBORDINAL			ulFailed	= 0;
	const DBORDINAL		cSameName	= 5;

	TESTC_PROVIDER(cSameName <= nThreads);
	TESTC_(CreateTableWithNoNullableColumns(&BaseTable, 0), S_OK);
	TESTC_(ReferencedTable.CreateTable(0), S_OK);
	ReferencedTable.AddInfoFromColumnsSchemaRowset(m_pITDWC, ReferencedTable.GetTableName());
	TESTC_(AddUniqueConstraint(&ReferencedTable, 1), S_OK);

	SAFE_ALLOC(m_prgTableID, DBID*, nThreads);
	SAFE_ALLOC(rgConstraintDesc, DBCONSTRAINTDESC, nThreads);
	SAFE_ALLOC(m_prgConstraintID, DBID*, nThreads);
	memset(rgConstraintDesc, 0, nThreads * sizeof(DBCONSTRAINTDESC));
	for (i=0; i< nThreads; i++)
	{
		m_rgResult[i] = -1;
		m_prgTableID[i]	= &BaseTable.GetTableIDRef();

		// create a constraint
		if (0 == i)
		{
			pConsDesc = new CPrimaryKeyCons(rgConstraintDesc+i);
			TESTC_(((CPrimaryKeyCons*)pConsDesc)->SetConstraint(&BaseTable, 1), S_OK);
		}
		else if (i%2)
		{
			pConsDesc = new CUniqueCons(rgConstraintDesc+i);
			TESTC_(((CUniqueCons*)pConsDesc)->SetConstraint(&BaseTable, 1), S_OK);
		}
		else
		{
			pConsDesc = new CForeignKeyCons(rgConstraintDesc+i);
			TESTC_(((CForeignKeyCons*)pConsDesc)->SetConstraint(&BaseTable, 1, rgCol, &ReferencedTable, 1, rgCol, m_SupportedMatchType), S_OK);
		}

		pConsDesc->MakeConstraintName();
		TESTC_(m_pITDWC->AddConstraint(m_prgTableID[i], &rgConstraintDesc[i]), S_OK);

		if (i < cSameName)
			m_prgConstraintID[i] = rgConstraintDesc[0].pConstraintID;
		else
			m_prgConstraintID[i] = rgConstraintDesc[i].pConstraintID;

		rgThreadParam[i].pObject	= this;
		rgThreadParam[i].i			= i;
	}
	
	// start the threads
	for (i=0; i<nThreads; i++)
	{
		hrgThread[i] = (HANDLE)_beginthreadex(NULL, 0, ThreadProc,
							(void*)&rgThreadParam[i],
							0, 
							&rgIDThread[i]);		// input param
		TESTC(0 != hrgThread[i]);
	}

	WaitForMultipleObjects(nThreads, (CONST HANDLE*)hrgThread, TRUE, 1000);
	Sleep(1000);
	for (i=0; i< nThreads; i++)
		CloseHandle(hrgThread[i]);

	for (i=0; i<nThreads; i++)
	{	
		if (S_OK != m_rgResult[i])
		{
			CHECK(m_rgResult[i], DB_E_NOCONSTRAINT);
			ulFailed++;

			if (	rgConstraintDesc[i].pConstraintID
				&&	DBKIND_NAME == rgConstraintDesc[i].pConstraintID->eKind
				&&	rgConstraintDesc[i].pConstraintID->uName.pwszName)
				odtLog << "Constraint " << rgConstraintDesc[i].pConstraintID->uName.pwszName << " failed to be added\n";
			else
				odtLog << "Constraint no " << i << " failed to be dropped\n";

			COMPARE(CheckResult(m_rgResult[i], cValidHRes, rgValidHRes), TRUE);
		}
		else
		{
			// get all the constraints associated with the table
			if (	m_prgTableID[i] 
				&&	DBKIND_NAME == m_prgTableID[i]->eKind 
				&&	CHECK(Constraints.GetConstraints(NULL, NULL, m_prgTableID[i]->uName.pwszName, NULL, NULL, NULL), S_OK))
			{
				COMPARE(NULL == Constraints[m_prgConstraintID[i]], TRUE);
			}
		}
	}

	TESTC(cSameName - 1 == ulFailed);

CLEANUP:
	BaseTable.DropTable();
	ReferencedTable.DropTable();
	SAFE_FREE(m_prgTableID);
	CHECK(FreeConstraintDesc(&cThreads, &rgConstraintDesc, TRUE), S_OK);
	SAFE_FREE(m_prgConstraintID);
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END



// {{ TCW_TERMINATE_METHOD
//*-----------------------------------------------------------------------
// @mfunc TestCase Termination Routine 
//
// @rdesc TEST_PASS or TEST_FAIL 
//
BOOL TCDropConstraint_Multithreading::Terminate()
{ 
	// TO DO:  Add your own code here 

// {{ TCW_TERM_BASECLASS_CHECK2
	return(TCITableDefinition::Terminate());
} 	// }}
// }} TCW_TERMINATE_METHOD_END
// }} TCW_TC_PROTOTYPE_END


// {{ TCW_TC_PROTOTYPE(TCCreateTableWithConstraints_Multithreading)
//*-----------------------------------------------------------------------
//| Test Case:		TCCreateTableWithConstraints_Multithreading - Multithreading test case for ITableDefinitionWithConstraints::CreateTableWithConstraints
//| Created:  	9/17/99
//*-----------------------------------------------------------------------

//*-----------------------------------------------------------------------
// @mfunc TestCase Initialization Routine
//
// @rdesc TRUE or FALSE
//
BOOL TCCreateTableWithConstraints_Multithreading::Init()
{ 
	// {{ TCW_INIT_BASECLASS_CHECK
	if(TCITableDefinition::Init())
	// }}
	{ 
		if (m_pITDWC == NULL)
		{
			odtLog << "ITableDefinitionWithConstraints is not supported.\n";
			return TEST_SKIPPED;
		}
		return TRUE;
	} 
	return FALSE;
} 




//---------------------------------------------------------------------
//
// @cmember Thread funtion for TCCreateTableWithConstraints_Multithreading
//---------------------------------------------------------------------
unsigned TCCreateTableWithConstraints_Multithreading::MyThreadProc(ULONG i)
{
	HRESULT			hr;

	if (i>= nThreads)
		return 0;

	Sleep(0); // switch the context

  	hr = m_pITDWC->CreateTableWithConstraints(
		m_rgThreadParams[i].m_pUnkOuter,
		m_rgThreadParams[i].m_pTableID,
		m_rgThreadParams[i].m_cColumnDescs,
		m_rgThreadParams[i].m_rgColumnDescs,
		m_rgThreadParams[i].m_cConstraintDescs,
		m_rgThreadParams[i].m_rgConstraintDescs,
		*m_rgThreadParams[i].m_piid,
		m_rgThreadParams[i].m_cPropertySets,
		m_rgThreadParams[i].m_rgPropertySets,
		m_rgThreadParams[i].m_ppTableID,
		m_rgThreadParams[i].m_ppRowset
		);
	Sleep(0); // switch the context

	m_rgThreadParams[i].m_hr = hr;
	return 1;
} //TCCreateTableWithConstraints_Multithreading::MyThreadProc




// {{ TCW_VAR_PROTOTYPE(1)
//*-----------------------------------------------------------------------
// @mfunc Each thread builds different table => all S_OK
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCCreateTableWithConstraints_Multithreading::Variation_1()
{ 
	TBEGIN
	CTable			ReferencedTable(m_pThisTestModule->m_pIUnknown2, (LPWSTR)gwszModuleName);
	DBCOLUMNDESC	*rgColumnDesc	= NULL;
	DBORDINAL		cColumnDesc		= 0;
	CConsDescArray	ConsDescArray[nThreads];
	ULONG			i;
	CCol			col;

	unsigned		rgIDThread[nThreads];
	HANDLE			hrgThread[nThreads];
	CInParam		rgThreadParam[nThreads];
	CConstraints	Constraints(m_pITDWC);

	m_rgThreadParams = NULL;

	DuplicateColumnDesc(m_rgColumnDesc, m_cColumnDesc, &rgColumnDesc);
	cColumnDesc = m_cColumnDesc;
	// release the properties on all column and make the first column not nullable
	ReleaseAllColumnPropSets(rgColumnDesc, cColumnDesc);
	SetProperty(&rgColumnDesc[0].rgPropertySets, &rgColumnDesc[0].cPropertySets,
			DBPROP_COL_NULLABLE, 
			VT_BOOL, (LPVOID)VARIANT_FALSE, 
			DBPROPOPTIONS_REQUIRED);

	// create support for foreign key constraint
	TESTC_(ReferencedTable.CreateTable(0, 0), S_OK);
	ReferencedTable.AddInfoFromColumnsSchemaRowset(m_pITDWC, ReferencedTable.GetTableName());
	// make the referenced columns unique
	TESTC_(AddUniqueConstraint(&ReferencedTable, 1, (DBDEFERRABILITY)0), S_OK);

	m_rgThreadParams = new CCTWCThreadParam[nThreads];
	for (i=0; i< nThreads; i++)
	{
		CUniqueCons		consUnique;
		CPrimaryKeyCons	consPrimaryKey;
		CForeignKeyCons	consForeignKey(NULL, m_SupportedMatchType);

		m_rgThreadParams[i].m_hr			= E_FAIL;
		m_rgThreadParams[i].m_op			= CREATETABLE_CONSTRAINTS;
		
		m_rgThreadParams[i].m_pUnkOuter		= NULL;
		m_rgThreadParams[i].m_pTableID		= NULL;
		
		m_rgThreadParams[i].m_cColumnDescs	= cColumnDesc;
		m_rgThreadParams[i].m_rgColumnDescs	= rgColumnDesc;
		
		// create the array of constraints
			// set a unique constraint on the second column
			consUnique.AddColumn(&rgColumnDesc[1].dbcid);

			// set a primary key on the first column of the table
			consPrimaryKey.AddColumn(&rgColumnDesc[0].dbcid);

			// set a simple foreign key constraint
			TESTC_(ReferencedTable.GetColInfo(1, col), S_OK);
			consForeignKey.AddColumn(col.GetColID());
			consForeignKey.AddForeignKeyColumn(&rgColumnDesc[0].dbcid);
			consForeignKey.SetReferencedTableID(&ReferencedTable.GetTableID());

			// add all constraint to the array
			ConsDescArray[i].AddConsDesc(consUnique);
			ConsDescArray[i].AddConsDesc(consForeignKey);
			ConsDescArray[i].AddConsDesc(consPrimaryKey);

		m_rgThreadParams[i].m_cConstraintDescs = ConsDescArray[i];
		m_rgThreadParams[i].m_rgConstraintDescs = ConsDescArray[i];
		
		m_rgThreadParams[i].m_piid			= NULL;
		m_rgThreadParams[i].m_cPropertySets	= 0;
		m_rgThreadParams[i].m_rgPropertySets= NULL;
	
		SAFE_ALLOC(m_rgThreadParams[i].m_ppTableID, DBID*, 1);
		//*m_rgThreadParams[i].m_ppTableID	= NULL;
		m_rgThreadParams[i].m_ppRowset		= NULL;

		rgThreadParam[i].pObject	= this;
		rgThreadParam[i].i			= i;
	}
	
	// start the threads
	for (i=0; i<nThreads; i++)
	{
		hrgThread[i] = (HANDLE)_beginthreadex(NULL, 0, ThreadProc,
							(void*)&rgThreadParam[i],
							0, 
							&rgIDThread[i]);		// input param
		TESTC(0 != hrgThread[i]);
	}

	WaitForMultipleObjects(nThreads, (CONST HANDLE*)hrgThread, TRUE, 1000);
	Sleep(1000);
	for (i=0; i< nThreads; i++)
		CloseHandle(hrgThread[i]);

	for (i=0; i<nThreads; i++)
	{	
		DBID	*pTableID = NULL;

		if (m_rgThreadParams[i].m_ppTableID)
			pTableID = (*m_rgThreadParams[i].m_ppTableID);
		else if (m_rgThreadParams[i].m_pTableID)
			pTableID = m_rgThreadParams[i].m_pTableID;

		if (CHECK(m_rgThreadParams[i].m_hr, S_OK))
		{
			COMPARE(NULL != pTableID, TRUE);

			// get all the constraints associated with the table
			if (	pTableID
				&&	DBKIND_NAME == pTableID->eKind 
				&&	CHECK(Constraints.GetConstraints(NULL, NULL, pTableID->uName.pwszName, NULL, NULL, NULL), S_OK))
			{
				CHECK(Constraints.CheckIncludedConstraints(m_rgThreadParams[i].m_cConstraintDescs, m_rgThreadParams[i].m_rgConstraintDescs), S_OK);
			}

			// drop the newly created table
			CHECK(m_pITableDefinition->DropTable(pTableID), S_OK);
		}
	}

CLEANUP:
	delete [] m_rgThreadParams;
	CHECK(ReferencedTable.DropTable(), S_OK);
	ReleaseColumnDesc(rgColumnDesc, cColumnDesc);
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END




// {{ TCW_VAR_PROTOTYPE(2)
//*-----------------------------------------------------------------------
// @mfunc Some threads build the same table => S_OK and DB_E_DUPLICATETABLEID
//
// @rdesc TEST_PASS or TEST_FAIL 
//
int TCCreateTableWithConstraints_Multithreading::Variation_2()
{ 
	TBEGIN
	CTable			ReferencedTable(m_pThisTestModule->m_pIUnknown2, (LPWSTR)gwszModuleName);
	DBCOLUMNDESC	*rgColumnDesc	= NULL;
	DBORDINAL		cColumnDesc		= 0;
	CConsDescArray	ConsDescArray[nThreads];
	ULONG			i;
	CCol			col;

	unsigned		rgIDThread[nThreads];
	HANDLE			hrgThread[nThreads];
	CInParam		rgThreadParam[nThreads];
	CConstraints	Constraints(m_pITDWC);
	WCHAR			*pwszBaseName = NULL;

	WCHAR			number[3];
	DBORDINAL		cSameName	= 5;
	DBORDINAL		cDuplicates	= 0;

	TESTC_PROVIDER(cSameName <= nThreads);
	m_rgThreadParams = NULL;

	DuplicateColumnDesc(m_rgColumnDesc, m_cColumnDesc, &rgColumnDesc);
	cColumnDesc = m_cColumnDesc;
	// release the properties on all column and make the first column not nullable
	ReleaseAllColumnPropSets(rgColumnDesc, cColumnDesc);
	SetProperty(&rgColumnDesc[0].rgPropertySets, &rgColumnDesc[0].cPropertySets,
			DBPROP_COL_NULLABLE, 
			VT_BOOL, (LPVOID)VARIANT_FALSE, 
			DBPROPOPTIONS_REQUIRED);

	// create support for foreign key constraint
	TESTC_(ReferencedTable.CreateTable(0, 0), S_OK);
	ReferencedTable.AddInfoFromColumnsSchemaRowset(m_pITDWC, ReferencedTable.GetTableName());
	// make the referenced columns unique
	TESTC_(AddUniqueConstraint(&ReferencedTable, 1, (DBDEFERRABILITY)0), S_OK);

	m_pTable->MakeTableName(NULL);
	pwszBaseName = m_pTable->GetTableName();

	m_rgThreadParams = new CCTWCThreadParam[nThreads];
	for (i=0; i< nThreads; i++)
	{
		CUniqueCons		consUnique;
		CPrimaryKeyCons	consPrimaryKey;
		CForeignKeyCons	consForeignKey(NULL, m_SupportedMatchType);

		m_rgThreadParams[i].m_hr			= E_FAIL;
		m_rgThreadParams[i].m_op			= CREATETABLE_CONSTRAINTS;
		
		m_rgThreadParams[i].m_pUnkOuter		= NULL;
		
		SAFE_ALLOC(m_rgThreadParams[i].m_pTableID, DBID, 1);
		m_rgThreadParams[i].m_pTableID->eKind = DBKIND_NAME;

		SAFE_ALLOC(m_rgThreadParams[i].m_pTableID->uName.pwszName, WCHAR,
			(3+wcslen(pwszBaseName)));		
		wcscpy(m_rgThreadParams[i].m_pTableID->uName.pwszName, pwszBaseName);
		swprintf(number, L"%02d", (i < cSameName)? 0: i);
		wcscat(m_rgThreadParams[i].m_pTableID->uName.pwszName, number);
		
		m_rgThreadParams[i].m_cColumnDescs	= cColumnDesc;
		m_rgThreadParams[i].m_rgColumnDescs	= rgColumnDesc;
		
		// create the array of constraints
			// set a unique constraint on the second column
			consUnique.AddColumn(&rgColumnDesc[1].dbcid);

			// set a primary key on the first column of the table
			consPrimaryKey.AddColumn(&rgColumnDesc[0].dbcid);

			// set a simple foreign key constraint
			TESTC_(ReferencedTable.GetColInfo(1, col), S_OK);
			consForeignKey.AddColumn(col.GetColID());
			consForeignKey.AddForeignKeyColumn(&rgColumnDesc[0].dbcid);
			consForeignKey.SetReferencedTableID(&ReferencedTable.GetTableID());

			// add all constraint to the array
			ConsDescArray[i].AddConsDesc(consUnique);
			ConsDescArray[i].AddConsDesc(consForeignKey);
			ConsDescArray[i].AddConsDesc(consPrimaryKey);

		m_rgThreadParams[i].m_cConstraintDescs = ConsDescArray[i];
		m_rgThreadParams[i].m_rgConstraintDescs = ConsDescArray[i];
		
		m_rgThreadParams[i].m_piid			= NULL;
		m_rgThreadParams[i].m_cPropertySets	= 0;
		m_rgThreadParams[i].m_rgPropertySets= NULL;
	
		m_rgThreadParams[i].m_ppTableID		= NULL;
		m_rgThreadParams[i].m_ppRowset		= NULL;

		rgThreadParam[i].pObject	= this;
		rgThreadParam[i].i			= i;
	}
	
	// start the threads
	for (i=0; i<nThreads; i++)
	{
		hrgThread[i] = (HANDLE)_beginthreadex(NULL, 0, ThreadProc,
							(void*)&rgThreadParam[i],
							0, 
							&rgIDThread[i]);		// input param
		TESTC(0 != hrgThread[i]);
	}

	WaitForMultipleObjects(nThreads, (CONST HANDLE*)hrgThread, TRUE, 1000);
	Sleep(1000);
	for (i=0; i< nThreads; i++)
		CloseHandle(hrgThread[i]);

	for (i=0; i<nThreads; i++)
	{	
		DBID	*pTableID = NULL;

		if (m_rgThreadParams[i].m_ppTableID)
			pTableID = (*m_rgThreadParams[i].m_ppTableID);
		else if (m_rgThreadParams[i].m_pTableID)
			pTableID = m_rgThreadParams[i].m_pTableID;

		if (S_OK == m_rgThreadParams[i].m_hr)
		{
			COMPARE(NULL != pTableID, TRUE);

			// get all the constraints associated with the table
			if (	pTableID
				&&	DBKIND_NAME == pTableID->eKind 
				&&	CHECK(Constraints.GetConstraints(NULL, NULL, pTableID->uName.pwszName, NULL, NULL, NULL), S_OK))
			{
				CHECK(Constraints.CheckIncludedConstraints(m_rgThreadParams[i].m_cConstraintDescs, m_rgThreadParams[i].m_rgConstraintDescs), S_OK);
			}

			// drop the newly created table
			CHECK(m_pITableDefinition->DropTable(pTableID), S_OK);
		}
		else
		{
			if (CHECK(m_rgThreadParams[i].m_hr, DB_E_DUPLICATETABLEID))
				cDuplicates++;
		}
	}

	TESTC(cDuplicates + 1 == cSameName);

CLEANUP:
	delete [] m_rgThreadParams;
	CHECK(ReferencedTable.DropTable(), S_OK);
	ReleaseColumnDesc(rgColumnDesc, cColumnDesc);
	TRETURN
} 
// }} TCW_VAR_PROTOTYPE_END



// {{ TCW_TERMINATE_METHOD
//*-----------------------------------------------------------------------
// @mfunc TestCase Termination Routine 
//
// @rdesc TEST_PASS or TEST_FAIL 
//
BOOL TCCreateTableWithConstraints_Multithreading::Terminate()
{ 
	// TO DO:  Add your own code here 

// {{ TCW_TERM_BASECLASS_CHECK2
	return(TCITableDefinition::Terminate());
} 	// }}
// }} TCW_TERMINATE_METHOD_END
// }} TCW_TC_PROTOTYPE_END




///////////////////////////////////////////////////////////////////////////
//
//		CAddConstraintTxnAdapter class
//
///////////////////////////////////////////////////////////////////////////
BOOL CAddConstraintTxnAdapter::BeforeTransaction() 
{
	TBEGIN

	// create a table and populate it
	TESTC_(pTCITableDefinition()->CreateTableWithNoNullableColumns(&m_Table, 0, 0), S_OK);
	m_Table.AddInfoFromColumnsSchemaRowset(g_pIOpenRowset, m_Table.GetTableName());

	// get the list of the constraints on the table
	m_pConstraints = new CConstraints(g_pIOpenRowset);
	TESTC_(m_pConstraints->GetConstraints(NULL, NULL, m_Table.GetTableName(), NULL, NULL, NULL), S_OK);

CLEANUP:
	TRETURN
} //CAddConstraintTxnAdapter::BeforeTransaction




///////////////////////////////////////////////////////////////////////////
//
//		CAddUniqueConsTxnAdapter class
//
///////////////////////////////////////////////////////////////////////////
BOOL CAddUniqueConsTxnAdapter::BeforeTransaction() 
{
	TBEGIN
	CCol	col;

	TESTC(CAddConstraintTxnAdapter::BeforeTransaction());

	// select column
	TESTC_(m_Table.GetColInfo(1, col), S_OK);

	// add the constraint
	m_pCons = new CUniqueCons();
	((CUniqueCons*)m_pCons)->AddColumn(col.GetColID());

CLEANUP:
	TRETURN
} //CAddUniqueConsTxnAdapter::BeforeTransaction



HRESULT CAddUniqueConsTxnAdapter::InsideTransactionScope()
{
	HRESULT	hr = E_FAIL;
	CCol	col;

	CHECK(CAddConstraintTxnAdapter::InsideTransactionScope(), S_OK);

	// create a table 
	TESTC_(pTCITableDefinition()->CreateTableWithNoNullableColumns(&m_TransactedTable, 0, 0), S_OK);
	m_TransactedTable.AddInfoFromColumnsSchemaRowset(g_pIOpenRowset, m_TransactedTable.GetTableName());

	// get the list of the constraints on the table
	m_pTxnConstraints = new CConstraints(g_pIOpenRowset);
	TESTC_(m_pTxnConstraints->GetConstraints(NULL, NULL, m_TransactedTable.GetTableName(), NULL, NULL, NULL), S_OK);

	// select column
	TESTC_(m_TransactedTable.GetColInfo(1, col), S_OK);

	// add the constraint
	m_pTransactedTableCons= new CUniqueCons();
	((CUniqueCons*)m_pTransactedTableCons)->AddColumn(col.GetColID());

	hr = m_pTCITableDefinition->AddConstraintAndCheck(
		m_pTCITableDefinition->pITDWC(), 
		&m_TransactedTable.GetTableID(), 
		*m_pTransactedTableCons);

CLEANUP:
	return hr;
} //CAddUniqueConsTxnAdapter::InsideTransactionScope



HRESULT CAddUniqueConsTxnAdapter::InsideTransactionOnDDLLock()
{
	HRESULT	hr = E_FAIL;
	CCol	col;

	CHECK(CAddConstraintTxnAdapter::InsideTransactionOnDDLLock(), S_OK);

	// create a table and populate it
	TESTC_(pTCITableDefinition()->CreateTableWithNoNullableColumns(&m_TransactedTable, 0, 0), S_OK);
	m_TransactedTable.AddInfoFromColumnsSchemaRowset(g_pIOpenRowset, m_TransactedTable.GetTableName());

	// select column
	TESTC_(m_TransactedTable.GetColInfo(1, col), S_OK);

	// add the constraint
	m_pTransactedTableCons = new CUniqueCons();
	((CUniqueCons*)m_pTransactedTableCons)->AddColumn(col.GetColID());

	// get the list of the constraints on the table
	m_pTxnConstraints = new CConstraints(g_pIOpenRowset);
	TESTC_(m_pTxnConstraints->GetConstraints(NULL, NULL, m_TransactedTable.GetTableName(), NULL, NULL, NULL), S_OK);

	hr = m_pTCITableDefinition->pITDWC()->AddConstraint(
		&m_TransactedTable.GetTableID(), 
		*m_pTransactedTableCons);

CLEANUP:
	return hr;
} //CAddUniqueConsTxnAdapter::InsideTransactionOnDDLLock



BOOL CAddUniqueConsTxnAdapter::CheckCompletion() 
{
	TBEGIN

	ASSERT(m_pCons);
	TESTC(CAddConstraintTxnAdapter::CheckCompletion());

	// check unique constraint here
	TESTC_(m_Table.Insert(5), S_OK);
	TESTC_(m_Table.Insert(5), DB_E_INTEGRITYVIOLATION);

	ASSERT(m_pTransactedTableCons);
	TESTC_(m_TransactedTable.Insert(5), S_OK);
	TESTC_(m_TransactedTable.Insert(5), DB_E_INTEGRITYVIOLATION);

CLEANUP:
	TRETURN
} //CAddUniqueConsTxnAdapter::CheckCompletion



BOOL CAddUniqueConsTxnAdapter::CheckRollBack() 
{
	TBEGIN

	ASSERT(m_pCons);
	TESTC(CAddConstraintTxnAdapter::CheckRollBack());

	// check unique constraint here
	TESTC_(m_Table.Insert(5), S_OK);
	TESTC_(m_Table.Insert(5), S_OK);

CLEANUP:
	TRETURN
} //CAddUniqueConsTxnAdapter::CheckRollBack




///////////////////////////////////////////////////////////////////////////
//
//		CAddPrimaryKeyConsTxnAdapter class
//
///////////////////////////////////////////////////////////////////////////
BOOL CAddPrimaryKeyConsTxnAdapter::BeforeTransaction()
{
	TBEGIN
	CCol	col;

	TESTC(CAddConstraintTxnAdapter::BeforeTransaction());

	// select column
	TESTC_(m_Table.GetColInfo(1, col), S_OK);

	// add the constraint
	m_pCons = new CPrimaryKeyCons();
	((CPrimaryKeyCons*)m_pCons)->AddColumn(col.GetColID());

CLEANUP:
	TRETURN
} //CAddPrimaryKeyConsTxnAdapter::BeforeTransaction



//////////////////////////////////////////////////////////////////
//
//		CAddFKConsTxnAdapter class
//
//////////////////////////////////////////////////////////////////
BOOL CAddFKConsTxnAdapter::BeforeTransaction() 
{
	TBEGIN
	CCol		col;
	CUniqueCons	uniqueCons;

	// create a reference table and populate it
	TESTC_(m_ReferencedTable.CreateTable(4, 0), S_OK);
	m_ReferencedTable.AddInfoFromColumnsSchemaRowset(g_pIOpenRowset, m_ReferencedTable.GetTableName());

	// add unique constraint on the first column
	TESTC_(m_ReferencedTable.GetColInfo(1, col), S_OK);
	uniqueCons.AddColumn(col.GetColID());
	CHECK(m_pTCITableDefinition->AddConstraintAndCheck(
		m_pTCITableDefinition->pITDWC(),
		&m_ReferencedTable.GetTableID(), uniqueCons), S_OK);

	// create a table and populate it
	TESTC_(m_Table.CreateTable(4, 0), S_OK);
	m_Table.AddInfoFromColumnsSchemaRowset(g_pIOpenRowset, m_Table.GetTableName());

	// get the list of the constraints on the table
	m_pConstraints = new CConstraints(g_pIOpenRowset);
	TESTC_(m_pConstraints->GetConstraints(NULL, NULL, m_Table.GetTableName(), NULL, NULL, NULL), S_OK);

	// prepare the constraint
	m_pCons = new CForeignKeyCons();

	// select column to be foreign key
	TESTC_(m_Table.GetColInfo(1, col), S_OK);
	((CForeignKeyCons*)m_pCons)->AddForeignKeyColumn(col.GetColID());
	TESTC_(m_ReferencedTable.GetColInfo(1, col), S_OK);
	((CForeignKeyCons*)m_pCons)->AddColumn(col.GetColID());
	((CForeignKeyCons*)m_pCons)->SetReferencedTableID(&m_ReferencedTable.GetTableID());

CLEANUP:
	TRETURN
} //CAddFKConsTxnAdapter::BeforeTransaction




HRESULT CAddFKConsTxnAdapter::InsideTransactionScope()
{
	HRESULT	hr = E_FAIL;
	CCol	col;

	CHECK(CAddConstraintTxnAdapter::InsideTransactionScope(), S_OK);

	// create a table and populate it
	TESTC_(pTCITableDefinition()->CreateTableWithNoNullableColumns(&m_TransactedTable, 0, 0), S_OK);
	m_TransactedTable.AddInfoFromColumnsSchemaRowset(g_pIOpenRowset, m_TransactedTable.GetTableName());

	// get the list of the constraints on the table
	m_pTxnConstraints = new CConstraints(g_pIOpenRowset);
	TESTC_(m_pTxnConstraints->GetConstraints(NULL, NULL, m_TransactedTable.GetTableName(), NULL, NULL, NULL), S_OK);

	// prepare the constraint
	m_pTransactedTableCons = new CForeignKeyCons();

	// select column
	TESTC_(m_TransactedTable.GetColInfo(1, col), S_OK);
	((CForeignKeyCons*)m_pTransactedTableCons)->AddForeignKeyColumn(col.GetColID());
	TESTC_(m_ReferencedTable.GetColInfo(1, col), S_OK);
	((CForeignKeyCons*)m_pTransactedTableCons)->AddColumn(col.GetColID());
	((CForeignKeyCons*)m_pTransactedTableCons)->SetReferencedTableID(&m_ReferencedTable.GetTableID());

	hr = m_pTCITableDefinition->AddConstraintAndCheck(
		m_pTCITableDefinition->pITDWC(),
		&m_TransactedTable.GetTableID(), 
		*m_pTransactedTableCons);

CLEANUP:
	return hr;
} //CAddFKConsTxnAdapter::InsideTransactionScope



HRESULT CAddFKConsTxnAdapter::InsideTransactionOnDDLLock()
{
	HRESULT	hr = E_FAIL;
	CCol	col;

	CHECK(CAddConstraintTxnAdapter::InsideTransactionOnDDLLock(), S_OK);

	// create a table and populate it
	TESTC_(pTCITableDefinition()->CreateTableWithNoNullableColumns(&m_TransactedTable, 0, 0), S_OK);
	m_TransactedTable.AddInfoFromColumnsSchemaRowset(g_pIOpenRowset, m_TransactedTable.GetTableName());

	// select column
	TESTC_(m_TransactedTable.GetColInfo(1, col), S_OK);

	// get the list of the constraints on the table
	m_pTxnConstraints = new CConstraints(g_pIOpenRowset);
	TESTC_(m_pTxnConstraints->GetConstraints(NULL, NULL, m_TransactedTable.GetTableName(), NULL, NULL, NULL), S_OK);

	// prepare the constraint
	m_pTransactedTableCons = new CForeignKeyCons();
	((CForeignKeyCons*)m_pTransactedTableCons)->AddColumn(col.GetColID());
	TESTC_(m_ReferencedTable.GetColInfo(1, col), S_OK);
	((CForeignKeyCons*)m_pTransactedTableCons)->AddForeignKeyColumn(col.GetColID());
	((CForeignKeyCons*)m_pTransactedTableCons)->SetReferencedTableID(&m_ReferencedTable.GetTableID());

	hr = m_pTCITableDefinition->pITDWC()->AddConstraint(
		&m_TransactedTable.GetTableID(), 
		*m_pTransactedTableCons);

CLEANUP:
	return hr;
} //CAddFKConsTxnAdapter::InsideTransactionOnDDLLock




BOOL CAddFKConsTxnAdapter::CheckCompletion() 
{
	TBEGIN

	ASSERT(m_pCons);
	TESTC(CAddConstraintTxnAdapter::CheckCompletion());

	// check foreign key constraint here
	TESTC_(m_Table.Insert(2), S_OK);
	// there isn't a row with seed 15 in the referenced table
	TESTC_(m_Table.Insert(15), DB_E_INTEGRITYVIOLATION);	

CLEANUP:
	TRETURN
} //CAddFKConsTxnAdapter::CheckCompletion



BOOL CAddFKConsTxnAdapter::CheckRollBack() 
{
	TBEGIN

	ASSERT(m_pCons);
	TESTC(CAddConstraintTxnAdapter::CheckRollBack());

	// check foreign key constraint here
	TESTC_(m_Table.Insert(2), S_OK);
	TESTC_(m_Table.Insert(15), S_OK);

CLEANUP:
	TRETURN
} //CAddFKConsTxnAdapter::CheckRollBack






//////////////////////////////////////////////////////////////////
//
//		CAddCheckConsTxnAdapter class
//
//////////////////////////////////////////////////////////////////
BOOL CAddCheckConsTxnAdapter::BeforeTransaction() 
{
	TBEGIN
	CCol		col;

	// create a table and populate it
	TESTC_(m_Table.CreateTable(0, 0), S_OK);
	m_Table.AddInfoFromColumnsSchemaRowset(g_pIOpenRowset, m_Table.GetTableName());

	// get the list of the constraints on the table
	m_pConstraints = new CConstraints(g_pIOpenRowset);
	TESTC_(m_pConstraints->GetConstraints(NULL, NULL, m_Table.GetTableName(), NULL, NULL, NULL), S_OK);

	// select column to be foreign key
	TESTC_(m_Table.GetColInfo(1, col), S_OK);

	// prepare the constraint
	m_pCons = new CCheckCons();
	// every 3rd row has a negative value
	CHECK(((CCheckCons*)m_pCons)->SetLTCheckConstraint(&m_Table, col.GetColNum(), 6), S_OK);

CLEANUP:
	TRETURN
} //CAddCheckConsTxnAdapter::BeforeTransaction



HRESULT	CAddCheckConsTxnAdapter::InsideTransactionScope()
{
	TBEGIN
	CCol		col;
	HRESULT		hr = E_FAIL;

	CHECK(CAddConstraintTxnAdapter::InsideTransactionScope(), S_OK);

	// create a table and populate it
	TESTC_(m_TransactedTable.CreateTable(0, 0), S_OK);
	m_Table.AddInfoFromColumnsSchemaRowset(g_pIOpenRowset, m_TransactedTable.GetTableName());

	// get the list of the constraints on the table
	m_pTxnConstraints = new CConstraints(g_pIOpenRowset);
	TESTC_(m_pTxnConstraints->GetConstraints(NULL, NULL, m_TransactedTable.GetTableName(), NULL, NULL, NULL), S_OK);

	// select column to be foreign key
	TESTC_(m_TransactedTable.GetColInfo(1, col), S_OK);

	// prepare the constraint
	m_pTransactedTableCons = new CCheckCons();
	// every 3rd row has a negative value
	CHECK(((CCheckCons*)m_pTransactedTableCons)->SetLTCheckConstraint(&m_TransactedTable, col.GetColNum(), 6), S_OK);

	hr = m_pTCITableDefinition->AddConstraintAndCheck(
			m_pTCITableDefinition->pITDWC(), 
			&m_TransactedTable.GetTableID(), *m_pTransactedTableCons);								

CLEANUP:
	return hr;
} //CAddCheckConsTxnAdapter::InsideTransactionScope



HRESULT CAddCheckConsTxnAdapter::InsideTransactionOnDDLLock()
{
	TBEGIN
	CCol		col;
	HRESULT		hr = E_FAIL;

	CHECK(CAddConstraintTxnAdapter::InsideTransactionOnDDLLock(), S_OK);

	// create a table and populate it
	TESTC_(m_TransactedTable.CreateTable(0, 0), S_OK);
	m_TransactedTable.AddInfoFromColumnsSchemaRowset(g_pIOpenRowset, m_TransactedTable.GetTableName());

	// get the list of the constraints on the table
	m_pTxnConstraints = new CConstraints(g_pIOpenRowset);
	TESTC_(m_pTxnConstraints->GetConstraints(NULL, NULL, m_TransactedTable.GetTableName(), NULL, NULL, NULL), S_OK);

	// select column to be foreign key
	TESTC_(m_TransactedTable.GetColInfo(1, col), S_OK);

	// prepare the constraint
	m_pTransactedTableCons = new CCheckCons();
	// every 3rd row has a negative value
	CHECK(((CCheckCons*)m_pTransactedTableCons)->SetLTCheckConstraint(&m_TransactedTable, col.GetColNum(), 6), S_OK);

	hr = m_pTCITableDefinition->pITDWC()->AddConstraint(
			&m_TransactedTable.GetTableID(), *m_pTransactedTableCons);
CLEANUP:
	return hr;
} //CAddCheckConsTxnAdapter::InsideTransactionOnDDLLock



BOOL CAddCheckConsTxnAdapter::CheckCompletion() 
{
	TBEGIN

	ASSERT(m_pCons);
	TESTC(CAddConstraintTxnAdapter::CheckCompletion());

	// check foreign key constraint here
	TESTC_(m_Table.Insert(4), S_OK);
	TESTC_(m_Table.Insert(8), DB_E_INTEGRITYVIOLATION);	

	TESTC_(m_TransactedTable.Insert(4), S_OK);
	TESTC_(m_TransactedTable.Insert(8), DB_E_INTEGRITYVIOLATION);	

CLEANUP:
	TRETURN
} //CAddCheckConsTxnAdapter::CheckCompletion



BOOL CAddCheckConsTxnAdapter::CheckRollBack() 
{
	TBEGIN

	ASSERT(m_pCons);
	TESTC(CAddConstraintTxnAdapter::CheckRollBack());

	// check constraint here
	TESTC_(m_Table.Insert(4), S_OK);
	TESTC_(m_Table.Insert(8), S_OK);

CLEANUP:
	TRETURN
} //CAddCheckConsTxnAdapter::CheckRollBack




////////////////////////////////////////////////////////
//
//	class CCreateTableWithConsTxnAdapter
//
////////////////////////////////////////////////////////
BOOL CCreateTableWithConsTxnAdapter::BeforeTransaction()
{
	TBEGIN
	CUniqueCons				consUnique;
	CPrimaryKeyCons			consPrimaryKey;
	CForeignKeyCons			consForeignKey(NULL, m_pTCITableDefinition->SupportedMatchType());
	DBORDINAL				rgReferencedCol[] = {1};
	CCol					col;
	CList <WCHAR*, WCHAR*>	ListNativeTemp;
	CList <DBTYPE, DBTYPE>	ListDataTypes;
	CList <CCol, CCol&>		ColList;

	// create table name
	m_Table.MakeTableName(NULL);

	// get the provider types list
	// all types appear in CreateColList, so I don't have to use CreateTypeColInfo
	m_Table.CreateTypeColInfo(ListNativeTemp, ListDataTypes, ALLTYPES);
	m_Table.DuplicateColList(ColList);

	// in m_rgColumnDesc I would rather load just the types prepared for table creation
	m_Table.CreateColInfo(ListNativeTemp, ListDataTypes, ALLTYPES);
	// build the column description array
	m_Table.BuildColumnDescs(&m_rgColumnDesc);
	m_cColumnDesc = m_Table.CountColumnsOnTable();
	m_Table.SetBuildColumnDesc(FALSE);

	// release the properties on all column and make the first column not nullable
	ReleaseAllColumnPropSets(m_rgColumnDesc, m_cColumnDesc);
	m_pTCITableDefinition->SetProperty(&m_rgColumnDesc[0].rgPropertySets, &m_rgColumnDesc[0].cPropertySets,
			DBPROP_COL_NULLABLE, 
			VT_BOOL, (LPVOID)VARIANT_FALSE, 
			DBPROPOPTIONS_REQUIRED);

	// create support for foreign key constraint
	TESTC_(m_RefTable.CreateTable(0, 0), S_OK);
	m_RefTable.AddInfoFromColumnsSchemaRowset(m_pTCITableDefinition->pITDWC(), m_RefTable.GetTableName());

	// make the referenced columns unique
	TESTC_(m_pTCITableDefinition->AddUniqueConstraint(&m_RefTable, rgReferencedCol[0], (DBDEFERRABILITY)0), S_OK);

	// set a unique constraint on the second column
	consUnique.AddColumn(&m_rgColumnDesc[1].dbcid);

	// set a primary key on the first column of the table
	consPrimaryKey.AddColumn(&m_rgColumnDesc[0].dbcid);

	// set a simple foreign key constraint
	TESTC_(m_RefTable.GetColInfo(1, col), S_OK);
	consForeignKey.AddColumn(col.GetColID());
	consForeignKey.AddForeignKeyColumn(&m_rgColumnDesc[0].dbcid);
	consForeignKey.SetReferencedTableID(&m_RefTable.GetTableID());

	// add all constraint to the array
	m_ConsDescArray.AddConsDesc(consUnique);
	m_ConsDescArray.AddConsDesc(consForeignKey);
	m_ConsDescArray.AddConsDesc(consPrimaryKey);

	// get the list of the constraints on the table
	m_pConstraints = new CConstraints(g_pIOpenRowset);
	TESTC_(m_pConstraints->GetConstraints(NULL, NULL, m_Table.GetTableName(), NULL, NULL, NULL), S_OK);

CLEANUP:
	TRETURN
} //CCreateTableWithConsTxnAdapter::BeforeTransaction



///////////////////////////////////////////////////////////
//
//	class CDropConsTxnAdapter
//
///////////////////////////////////////////////////////////
BOOL CDropConsTxnAdapter::BeforeTransaction()
{
	TBEGIN
	CCol				col;

	TESTC_(pTCITableDefinition()->CreateTableWithNoNullableColumns(&m_Table, 0, 0), S_OK);
	m_Table.AddInfoFromColumnsSchemaRowset(m_pTCITableDefinition->pITDWC(), m_Table.GetTableName());
	
	TESTC_(pTCITableDefinition()->CreateTableWithNoNullableColumns(&m_RefTable, 0, 0), S_OK);
	m_RefTable.AddInfoFromColumnsSchemaRowset(m_pTCITableDefinition->pITDWC(), m_RefTable.GetTableName());
	TESTC_(m_pTCITableDefinition->AddUniqueConstraint(&m_RefTable, 1), S_OK);

	// choose 1 column and create a unique constraint on them
	TESTC_(m_Table.GetColInfo(1, col), S_OK);
	m_pFKCons = new CForeignKeyCons(NULL, m_pTCITableDefinition->SupportedMatchType());
	m_pFKCons->AddForeignKeyColumn(col.GetColID());

	TESTC_(m_RefTable.GetColInfo(1, col), S_OK);
	m_pFKCons->AddColumn(col.GetColID());

	m_pFKCons->SetReferencedTableID(&m_RefTable.GetTableID());

	CHECK(m_pTCITableDefinition->AddConstraintAndCheck(m_pTCITableDefinition->pITDWC(), &m_Table.GetTableID(), *m_pFKCons), S_OK);

	// Add constraint
	m_pPKCons = new CPrimaryKeyCons();
	m_pPKCons->AddColumn(col.GetColID());
	CHECK(m_pTCITableDefinition->AddConstraintAndCheck(m_pTCITableDefinition->pITDWC(), &m_Table.GetTableID(), *m_pPKCons), S_OK);

	// Add constraint
	m_pUniqueCons = new CUniqueCons();
	m_pUniqueCons->AddColumn(col.GetColID());
	CHECK(m_pTCITableDefinition->AddConstraintAndCheck(m_pTCITableDefinition->pITDWC(), &m_Table.GetTableID(), *m_pUniqueCons), S_OK);

	// Add constraint
	m_pCheckCons = new CCheckCons();
	m_pCheckCons->SetLTCheckConstraint(&m_Table, col.GetColNum(), 5);
	CHECK(m_pTCITableDefinition->AddConstraintAndCheck(m_pTCITableDefinition->pITDWC(), &m_Table.GetTableID(), *m_pCheckCons), S_OK);

	// get the list of the constraints on the table
	m_pConstraints = new CConstraints(g_pIOpenRowset);
	CHECK(m_pConstraints->GetConstraints(NULL, NULL, m_Table.GetTableName(), NULL, NULL, NULL), S_OK);

CLEANUP:
	TRETURN
} //CDropConsTxnAdapter::BeforeTransaction




HRESULT CTransactionLocal::StartTransaction(
	IUnknown				*pISessionUnknown,
	// arguments for ITransactionLocal::StartTransaction
	ISOLEVEL                isoLevel,
	ULONG                   isoFlags,
	ITransactionOptions		*pOtherOptions						
)
{
	HRESULT		hr = E_FAIL;
	CPropSets	PropSets;
	DBPROP		*pSupportedTxnDDL;

	m_lSupportedTxnDDL = DBPROPVAL_TC_NONE;

	if (!pISessionUnknown)
		return E_INVALIDARG;

	m_Session = pISessionUnknown;
	
	TESTC_(m_Session.GetDataSource(m_DataSource), S_OK);
	
	// get DBPROP_SUPPORTEDTXNDDL
	TESTC_(m_DataSource.GetProperties(&PropSets), S_OK);
	pSupportedTxnDDL = PropSets.FindProperty(DBPROP_SUPPORTEDTXNDDL, DBPROPSET_DATASOURCEINFO);
	
	TESTC(!pSupportedTxnDDL || (VT_I4 == pSupportedTxnDDL->vValue.vt));
	if (pSupportedTxnDDL)
		m_lSupportedTxnDDL = V_I4(&pSupportedTxnDDL->vValue);
	else if ((ITransactionLocal*)m_Session)
		m_lSupportedTxnDDL = DBPROPVAL_TC_ALL;

	// check the relation between the property and the interface
	TESTC(	(NULL != (ITransactionLocal*)m_Session)
		||	(!pSupportedTxnDDL || (DBPROPVAL_TC_NONE == m_lSupportedTxnDDL)));

	// if the interface is not supported just return
	if (NULL == (ITransactionLocal*)m_Session)
		return S_OK;

	hr = ((ITransactionLocal*)m_Session)->StartTransaction(isoLevel, isoFlags, pOtherOptions, NULL);

	if (hr==S_OK)
		// Set the flag that we're inside transaction
		CConsDesc::s_fInsideTransaction = TRUE;

CLEANUP:
	return hr;
} //CTransactionLocal::StartTransaction



BOOL CTransactionLocal::DoTransactionTest(
	IUnknown				*pISessionUnknown,
	CTransactionAdapter		*pTAdapter,
	// arguments for ITransactionLocal::Abort / Commit
	BOOL					fDDL,			// whether or not this is a DDL call
   	BOOL					fAbortCommit,	// whether to abort or commit
	BOOL					fRetaining		// if it's retaining or not
)
{
	TBEGIN
	HRESULT		hr;
	ULONG		cIsoLevel, i;
	ISOLEVEL	rgIsoLevel[] = {ISOLATIONLEVEL_BROWSE, ISOLATIONLEVEL_CURSORSTABILITY,
								ISOLATIONLEVEL_ISOLATED, ISOLATIONLEVEL_CHAOS};
	cIsoLevel = NUMELEM(rgIsoLevel);

	TESTC(NULL != pISessionUnknown);
	TESTC(NULL != pTAdapter);

	m_pTAdapter = pTAdapter;

	// do work / testing that precedes transaction
	COMPARE(m_pTAdapter->BeforeTransaction(), TRUE);

	// start the transaction
	for (i=0; i<cIsoLevel; i++)
	{
		if (S_OK == (hr = StartTransaction(pISessionUnknown, rgIsoLevel[i], 0, NULL)))
			break;
	}
	if (cIsoLevel < i)
		return E_FAIL;

	//	TESTC_(m_pTAdapter->pTCITableDefinition()->StartTransaction(), S_OK);
//	TESTC_(StartTransaction(pISessionUnknown, isoLevel, isoFlags, pOtherOptions), S_OK);

	// check that we have a local transaction; return if not 
	TESTC_PROVIDER(NULL != (ITransactionLocal*)m_Session);
	
	if (!fDDL)
	{	TESTC_(m_pTAdapter->InsideTransactionScope(), S_OK);}
	else
	{
		switch (m_lSupportedTxnDDL)
		{
			case DBPROPVAL_TC_DML:
				//check for XACT_E_XTIONEXISTS
				CHECK(hr = m_pTAdapter->InsideTransactionScope(), XACT_E_XTIONEXISTS);
				break;

			case DBPROPVAL_TC_DDL_IGNORE:
				// the statement is not transacted
			case DBPROPVAL_TC_ALL:
			case DBPROPVAL_TC_DDL_COMMIT:
				CHECK(hr = m_pTAdapter->InsideTransactionScope(), S_OK);
				break;

			case DBPROPVAL_TC_DDL_LOCK:
				CHECK(hr = m_pTAdapter->InsideTransactionOnDDLLock(), S_OK);
				break;
				
			default:
				TESTC(FALSE);
		}
	}

	// end transaction
	if (!fDDL || (DBPROPVAL_TC_DDL_COMMIT != m_lSupportedTxnDDL))
	{
		if (fAbortCommit)
		{
			CHECK(Abort(NULL, fRetaining, FALSE), S_OK);		
		}
		else
		{
			CHECK(Commit(fRetaining, 0, 0), S_OK);
		}
	}

	// check the result of the operation
	if (	
			// DDL and aborted but prop is DDL ignore or DDL commit
			(	fDDL 
			&&	(	(DBPROPVAL_TC_DDL_COMMIT == m_lSupportedTxnDDL)
					||	(DBPROPVAL_TC_DDL_IGNORE == m_lSupportedTxnDDL))
			//&&	fAbortCommit	// this is not necessary
			)
			// DDL and committed but prop is DML
		||	(	fDDL
			&&	(DBPROPVAL_TC_DML == m_lSupportedTxnDDL)
			//&&	!fAbortCommit	// this is not necessary
			)	
			// operation is not a DDL and txn is committed
		||	!fAbortCommit)
		COMPARE(m_pTAdapter->CheckCompletion(), TRUE);
	else
		COMPARE(m_pTAdapter->CheckRollBack(), TRUE);

	// end this transaction
	CHECK(Commit(FALSE, 0, 0), fRetaining? S_OK: XACT_E_NOTRANSACTION);
	CHECK(Abort(NULL, FALSE, FALSE), XACT_E_NOTRANSACTION);		

CLEANUP:
	CConsDesc::s_fInsideTransaction = FALSE;
	TRETURN
} //CTransactionLocal::DoTransactionTest





