2025-11-28 00:35:46 +09:00

9366 lines
277 KiB
C++

//*-----------------------------------------------------------------------
//
// This is the Test Module for IAlterIndex interface, which is an
// optional interface on Session objects.
//
// WARNING:
// PLEASE USE THE TEST CASE WIZARD TO ADD/DELETE TESTS AND VARIATIONS!
//
//
// Copyright (C) 1994-1997 Microsoft Corporation
//*-----------------------------------------------------------------------
#include "MODStandard.hpp"
#include "IAlterIndex.h"
#include "ExtraLib.h"
//*-----------------------------------------------------------------------
// Global vars
//*-----------------------------------------------------------------------
BOOL g_fBadInitialSize = FALSE; // Used to suppress duplicate errors
//*-----------------------------------------------------------------------
// Module Values
//*-----------------------------------------------------------------------
// {{ TCW_MODULE_GLOBALS
DECLARE_MODULE_CLSID = { 0x6522f900, 0x46d5, 0x11d3, { 0x89, 0x3d, 0x00, 0x60, 0x08, 0x9f, 0xc4, 0x66} };
DECLARE_MODULE_NAME("IAlterIndex");
DECLARE_MODULE_OWNER("Microsoft");
DECLARE_MODULE_DESCRIP("Testsuite for IAlterIndex interface.");
DECLARE_MODULE_VERSION(1);
// TCW_WizardVersion(2)
// TCW_Automation(FALSE)
// }} TCW_MODULE_GLOBALS_END
//*-----------------------------------------------------------------------
// @func Module level initialization routine
//
// @rdesc Success or Failure
// @flag TRUE | Successful initialization
// @flag FALSE | Initialization problems
//
BOOL ModuleInit(CThisTestModule * pThisTestModule)
{
TBEGIN
IAlterIndex* pIAlterIndex = NULL;
g_fBadInitialSize = FALSE;
//Create the session
TESTC(ModuleCreateDBSession(pThisTestModule))
TESTC_PROVIDER(VerifyInterface(pThisTestModule->m_pIUnknown2,
IID_IAlterIndex, SESSION_INTERFACE, (IUnknown**)&pIAlterIndex))
//g_pIDBInitialize needed for some Extralib functions.
TESTC(VerifyInterface(pThisTestModule->m_pIUnknown,
IID_IDBInitialize, DATASOURCE_INTERFACE, (IUnknown**)
&g_pIDBInitialize))
CLEANUP:
SAFE_RELEASE(pIAlterIndex);
TRETURN
}
//*-----------------------------------------------------------------------
// @func Module level termination routine
//
// @rdesc Success or Failure
// @flag TRUE | Successful initialization
// @flag FALSE | Initialization problems
//
BOOL ModuleTerminate(CThisTestModule * pThisTestModule)
{
SAFE_RELEASE(g_pIDBInitialize);
return ModuleReleaseDBSession(pThisTestModule);
}
class CVARIANT : public VARIANT
{
public:
CVARIANT(VARTYPE vt, VARIANT_BOOL bValue)
{
VariantInit(this);
this->vt = vt;
this->boolVal = bValue;
}
};
class CDBID : public DBID
{
public:
CDBID(DBKIND eKindNew, LPWSTR pwszNameNew)
{
uGuid.guid = GUID_NULL;
uGuid.pguid = NULL;
eKind = eKindNew;
uName.pwszName = pwszNameNew;
}
};
class CIndexInfo
{
private:
DBID m_TableID;
DBID m_IndexID;
DBID * m_pTableID;
DBID * m_pIndexID;
LPBYTE m_pData;
DBBINDING * m_pBinding;
DBLENGTH m_ulRowSize;
ULONG m_cIndexCols;
IDBSchemaRowset * m_pIDBSchemaRowset;
IOpenRowset * m_pIOpenRowset;
void ReleaseAll(void);
HRESULT GetIndexInfo(void);
HRESULT RefreshIndexInfo(void);
DBLENGTH GetIndexValueLength(ULONG iIndexCol, enum EINDEXSCHEMA iIndexValue);
public:
CIndexInfo(void);
~CIndexInfo(void);
BOOL Init(IUnknown * pSessionUnknown, DBID *pTableID, DBID *pIndexID);
BOOL IsIndexValueValid(ULONG iIndexCol, enum EINDEXSCHEMA iIndexValue);
LPBYTE GetIndexValuePtr(ULONG iIndexCol, enum EINDEXSCHEMA iIndexValue);
};
CIndexInfo::CIndexInfo(void)
{
m_pTableID = &m_TableID;
m_pIndexID = &m_IndexID;
memset(m_pTableID, 0, sizeof(DBID));
memset(m_pIndexID, 0, sizeof(DBID));
m_pData = NULL;
m_pBinding = NULL;
m_ulRowSize = 0;
m_cIndexCols = 0;
m_pIDBSchemaRowset = NULL;
m_pIOpenRowset = NULL;
}
CIndexInfo::~CIndexInfo(void)
{
// Release/free member vars
ReleaseAll();
}
void CIndexInfo::ReleaseAll(void)
{
if (m_pTableID)
ReleaseDBID(m_pTableID, FALSE);
if (m_pIndexID)
ReleaseDBID(m_pIndexID, FALSE);
SAFE_FREE(m_pData);
SAFE_FREE(m_pBinding);
SAFE_RELEASE(m_pIDBSchemaRowset);
SAFE_RELEASE(m_pIOpenRowset);
}
BOOL CIndexInfo::Init(IUnknown * pSessionUnknown, DBID *pTableID, DBID *pIndexID)
{
// Validate args
if (!pSessionUnknown || !pTableID)
return FALSE;
// Release/free member vars
ReleaseAll();
// Save table and index ID
TESTC_(DuplicateDBID(*pTableID, m_pTableID), S_OK);
if (pIndexID)
{
TESTC_(DuplicateDBID(*pIndexID, m_pIndexID), S_OK);
}
else
m_pIndexID = NULL;
// Get IDBSchemaRowset interface. We assume all providers will support this as
// otherwise there's no way to know what indexes have been created.
if (!VerifyInterface(pSessionUnknown,
IID_IDBSchemaRowset, SESSION_INTERFACE, (IUnknown**)&m_pIDBSchemaRowset))
return FALSE;
if (!VerifyInterface(pSessionUnknown,
IID_IOpenRowset, SESSION_INTERFACE, (IUnknown**)&m_pIOpenRowset))
return FALSE;
return (S_OK == GetIndexInfo());
CLEANUP:
return FALSE;
}
HRESULT CIndexInfo::RefreshIndexInfo(void)
{
SAFE_FREE(m_pData);
SAFE_FREE(m_pBinding);
return GetIndexInfo();
}
DBLENGTH CIndexInfo::GetIndexValueLength(ULONG iIndexCol, enum EINDEXSCHEMA iIndexValue)
{
if (!IsIndexValueValid(iIndexCol, iIndexValue))
return 0;
if (!LENGTH_IS_BOUND(m_pBinding[iIndexValue]))
return 0;
return LENGTH_BINDING(m_pBinding[iIndexValue], m_pData+iIndexCol*m_ulRowSize);
}
BOOL CIndexInfo::IsIndexValueValid(ULONG iIndexCol, enum EINDEXSCHEMA iIndexValue)
{
if (!m_pData || !m_pBinding)
return FALSE;
if (iIndexCol >= m_cIndexCols)
return FALSE;
if (iIndexCol > 0 && m_ulRowSize == 0)
return 0;
if (!STATUS_IS_BOUND(m_pBinding[iIndexValue]))
return 0;
if (!VALUE_IS_BOUND(m_pBinding[iIndexValue]))
return 0;
return (DBSTATUS_S_OK == STATUS_BINDING(m_pBinding[iIndexValue], m_pData+iIndexCol*m_ulRowSize));
}
LPBYTE CIndexInfo::GetIndexValuePtr(ULONG iIndexCol, enum EINDEXSCHEMA iIndexValue)
{
if (!IsIndexValueValid(iIndexCol, iIndexValue))
return NULL;
return (LPBYTE)&VALUE_BINDING(m_pBinding[iIndexValue], m_pData+iIndexCol*m_ulRowSize);
}
HRESULT CIndexInfo::GetIndexInfo(void)
{
HRESULT hr = E_FAIL;
IRowsetIndex * pIRowsetIndex = NULL;
DBLENGTH ulBufferSize = 0;
ULONG cRows = 0;
LPBYTE pRow = NULL;
DBORDINAL cKeyColumns = 0;
DBINDEXCOLUMNDESC * rgIndexColumnDesc = NULL;
ULONG cIndexPropSets = 0;
DBPROPSET * rgIndexPropSets = NULL;
BOOL fReturn = FALSE;
BOOL fProps = TRUE;
BOOL bIsSchemaSupported;
ULONG ulRowSize = 0; // size of row
DBCOUNTITEM cDBBINDING = 0; // count of bindings
ULONG iRow = 0; // count of rows
DBCOUNTITEM cRowsObtained = 0; // number of rows returned, should be 1
ULONG cSchema = 0; // number of supported Schemas
ULONG *prgRestrictions= 0; // restrictions for each Schema
GUID *prgSchemas = NULL; // array of GUIDs
HROW hRow; // handler of rows
HROW *phRow = &hRow; // pointer to handler
IRowset *pIndexRowset = NULL; // returned rowset
DBBINDING *rgDBBINDING = NULL; // array of bindings
HACCESSOR hAccessor = NULL; // accessor
BOOL *rgColPresent = NULL;
const int cRest = 5;
VARIANT rgRestrictIndexes[cRest];
ULONG index, i;
// column entries in index schema rowset and their presence flags
LPWSTR pwszIndexName = NULL;
BOOL fIndexName = FALSE;
LPWSTR pwszTableName = NULL;
BOOL fTableName = FALSE;
// We need IDBSchemaRowset for verification.
if (!m_pIDBSchemaRowset)
return E_FAIL;
if (m_pIndexID)
{
// Try to get IRowsetIndex from integrated index
TEST3C_(hr = m_pIOpenRowset->OpenRowset(
NULL,
m_pTableID,
m_pIndexID,
IID_IRowsetIndex,
0,
NULL,
(IUnknown**)&pIRowsetIndex
), S_OK, E_NOINTERFACE, DB_E_NOINDEX);
if (FAILED(hr))
{
// Try to get IRowsetIndex from separate index
TEST3C_(hr = m_pIOpenRowset->OpenRowset(
NULL,
NULL,
m_pIndexID,
IID_IRowsetIndex,
0,
NULL,
(IUnknown**)&pIRowsetIndex
), S_OK, E_NOINTERFACE, DB_E_NOINDEX);
if (SUCCEEDED(hr))
TESTC(pIRowsetIndex != NULL);
}
}
if (pIRowsetIndex)
{
TESTC_(pIRowsetIndex->GetIndexInfo(
&cKeyColumns,
&rgIndexColumnDesc,
&cIndexPropSets,
&rgIndexPropSets), S_OK);
}
// Initialize restrictions
for(index=0;index<cRest;index++)
VariantInit(&rgRestrictIndexes[index]);
// Check to see if the schema is supported
TESTC_(hr = m_pIDBSchemaRowset->GetSchemas(&cSchema, &prgSchemas, &prgRestrictions),S_OK);
if (m_pIndexID)
{
if (DBKIND_NAME == m_pIndexID->eKind)
{
pwszIndexName = wcsDuplicate(m_pIndexID->uName.pwszName);
fIndexName = TRUE;
}
}
if (DBKIND_NAME == m_pTableID->eKind)
{
pwszTableName = wcsDuplicate(m_pTableID->uName.pwszName);
fTableName = TRUE;
}
// Check to see if DBSCHEMA_INDEXES is supported
for(i=0, bIsSchemaSupported=FALSE; i<cSchema && !bIsSchemaSupported;)
{
if(prgSchemas[i] == DBSCHEMA_INDEXES)
bIsSchemaSupported = TRUE;
else
i++;
}
if(!bIsSchemaSupported || !(prgRestrictions[i] & 0x4) || !(prgRestrictions[i] & 0x10))
{
odtLog << "Index Schema Rowset or the required constraints are not supported\n";
goto CLEANUP;
}
if (m_pIndexID)
{
rgRestrictIndexes[2].vt = VT_BSTR;
rgRestrictIndexes[2].bstrVal = SysAllocString(m_pIndexID->uName.pwszName);
}
rgRestrictIndexes[4].vt = VT_BSTR;
rgRestrictIndexes[4].bstrVal = SysAllocString(m_pTableID->uName.pwszName);
TESTC_(hr = m_pIDBSchemaRowset->GetRowset(
NULL, // aggregation
DBSCHEMA_INDEXES, // REFGUID
cRest, // count of restrictions (1:types)
rgRestrictIndexes, // list of restrictions
IID_IRowset, // REFFID
0, // count of properties
NULL, // range of properties
(IUnknown**)&pIndexRowset // returned result set
),S_OK);
TESTC_(hr = GetAccessorAndBindings(
pIndexRowset, DBACCESSOR_ROWDATA, &hAccessor, &m_pBinding,
&cDBBINDING, &m_ulRowSize, DBPART_VALUE |DBPART_STATUS |DBPART_LENGTH,
ALL_COLS_EXCEPTBOOKMARK, FORWARD, NO_COLS_BY_REF,
NULL, // OUT: Array of DBCOLUMNINFOs
0, // OUT: Count of DBCOULMNINFOs
NULL, //&pStringsBuffer,
DBTYPE_EMPTY,
0, NULL),S_OK);
// read the first row, check local data and initialize variables
// Read all the rows and verify the columns that were indexed and
// their collation, ordinal position, etc.
// Also verify integrated based on how openrowset performs.
hr = S_OK;
ASSERT(m_pData == NULL);
while (hr == S_OK)
{
TEST2C_(hr=pIndexRowset->GetNextRows(0, 0, 1, &cRowsObtained, &phRow), S_OK, DB_S_ENDOFROWSET);
if (hr == DB_S_ENDOFROWSET)
break;
TESTC(cRowsObtained == 1);
// Allocate buffer for row of data
ulBufferSize = m_ulRowSize*(cRows+1);
SAFE_REALLOC(m_pData, BYTE, ulBufferSize);
pRow = m_pData+cRows*m_ulRowSize;
// Retrieve the row
TESTC_(hr=pIndexRowset->GetData(hRow, hAccessor, pRow),S_OK);
TESTC_(pIndexRowset->ReleaseRows(1, &hRow, NULL, NULL, NULL), S_OK);\
// Now we have one more row in our buffer
cRows++;
}
// Make sure we got end of rowset
TESTC_(hr, DB_S_ENDOFROWSET);
// Make sure we got at least one row from the index
TESTC(cRows > 0);
m_cIndexCols = cRows;
// If we have both types of information then compare them
if (pIRowsetIndex && m_pIDBSchemaRowset)
{
// Compare schema information from IRowsetIndex and DBSCHEMA_INDEXES
// Count of rows from schema rowset should match number of key colummns
if (COMPARE(cKeyColumns, cRows))
{
// Each row should match appropriate value from IRowset::GetIndexInfo
for (ULONG iRow=0; iRow < cRows; iRow++)
{
DBID * pColumnID = rgIndexColumnDesc[iRow].pColumnID;
DBINDEX_COL_ORDER eIndexColOrder = rgIndexColumnDesc[iRow].eIndexColOrder;
BOOL fIndexPropSet = FALSE;
// IRowsetIndex::GetIndexInfo doesn't return information about catalog, schema, and
// table, but those must have matched or we won't find the index. We could match
// if index id is fully qualified, or else if we use current catalog.
// If DBID has name, we can compare with name in schema rowset
if (pColumnID && DBIDHasName(*pColumnID) && IsIndexValueValid(iRow, IS_COLUMN_NAME))
COMPARE(wcscmp(pColumnID->uName.pwszName, (LPWSTR)GetIndexValuePtr(iRow, IS_COLUMN_NAME)), 0);
// TODO: Compare propid, guid, etc. But at this time no providers support those.
// The index order should match. Note values differ, schema rowset is 1 based
// while DBINDEX_COL_ORDER is 0 based. Also, DBINDEX_COL_ORDER is ULONG, while
// COLLATION is SHORT.
if (IsIndexValueValid(iRow, IS_COLLATION))
COMPARE(eIndexColOrder, (ULONG)(*(SHORT *)GetIndexValuePtr(iRow, IS_COLLATION))-1);
// The ordinal should match
if (IsIndexValueValid(iRow, IS_ORDINAL_POSITION))
COMPARE(iRow+1, (*(ULONG *)GetIndexValuePtr(iRow, IS_ORDINAL_POSITION)));
// Compare all the properties
for (ULONG iPropSet = 0; iPropSet < cIndexPropSets; iPropSet++)
{
// We can't compare any provider specific index prop sets
if (rgIndexPropSets[iPropSet].guidPropertySet != DBPROPSET_INDEX)
continue;
fIndexPropSet = TRUE;
for (ULONG iProp = 0; iProp < rgIndexPropSets[iPropSet].cProperties; iProp++)
{
ULONG iMap;
// Find this prop in the mapping
for (iMap = 0; iMap < NUMELEM(IndexProperties); iMap++)
if (rgIndexPropSets[iPropSet].rgProperties[iProp].dwPropertyID ==
IndexProperties[iMap].dwProp)
break;
// We use the enum value of CINDEXFIELDS to indicate no corresponding field in INDEXES rowset
// We can't compare values with no corresponding INDEXES field.
if (IndexProperties[iMap].eSchemaField == CINDEXFIELDS)
break;
// We must find the prop
if (COMPARE(iMap < NUMELEM(IndexProperties), TRUE))
{
// Extract the values
LPBYTE pPropVal = &rgIndexPropSets[iPropSet].rgProperties[iProp].vValue.bVal;
LPBYTE pSchemaVal = GetIndexValuePtr(iRow, IndexProperties[iMap].eSchemaField);
DBLENGTH ulLength = GetIndexValueLength(iRow, IndexProperties[iMap].eSchemaField);
// If we got valid data for each value we can compare them
if (COMPARE(pPropVal != NULL, TRUE) &&
COMPARE(pSchemaVal != NULL, TRUE) &&
IsIndexValueValid(iRow, IndexProperties[iMap].eSchemaField))
{
// Perform compare, suppress duplicate failures for INITIALSIZE
if (rgIndexPropSets[iPropSet].rgProperties[iProp].dwPropertyID ==
DBPROP_INDEX_INITIALSIZE)
{
if (!g_fBadInitialSize && !COMPARE(memcmp(pPropVal, pSchemaVal, (size_t)ulLength) == 0, TRUE))
{
odtLog << L"Property " << IndexProperties[iMap].pwszPropVal << L" had an invalid value.\n\n";
g_fBadInitialSize = TRUE;
}
}
else
{
// Perform compare
if (!COMPARE(memcmp(pPropVal, pSchemaVal, (size_t)ulLength) == 0, TRUE))
odtLog << L"Property " << IndexProperties[iMap].pwszPropVal << L" had an invalid value.\n\n";
}
}
}
}
}
// We have to find the index propset in the property sets
COMPARE(fIndexPropSet, TRUE);
}
}
}
// Reset to S_OK
hr = S_OK;
CLEANUP:
// Free the memory
SAFE_FREE(pwszIndexName);
SAFE_FREE(pwszTableName);
SAFE_FREE(rgColPresent);
SAFE_FREE(prgRestrictions);
SAFE_FREE(prgSchemas);
SAFE_RELEASE(pIndexRowset);
SAFE_RELEASE(pIRowsetIndex);
for(index=0;index<cRest;index++)
GCHECK(VariantClear(&(rgRestrictIndexes[index])),S_OK);
return hr;
}
////////////////////////////////////////////////////////////////////////
// TCBase - Class for reusing Test Cases.
// This is one of the base classes from which all the Test Case
// classes will inherit. It is used to duplicate test cases, yet
// maintain some sort of distinct identity for each.
//
////////////////////////////////////////////////////////////////////////
class TCBase
{
public:
//constructor
TCBase() { SetTestCaseParam(TC_SingleColNoProps); }
virtual void SetTestCaseParam(ETESTCASE eTestCase)
{
m_eTestCase = eTestCase;
switch(eTestCase)
{
case TC_SingleColNoProps:
break;
case TC_SingleColProps:
break;
case TC_MultipleColsNoProps:
break;
case TC_MultipleColsProps:
break;
case TC_PropSingCol:
break;
case TC_PropMultCol:
break;
default:
ASSERT(!L"Unhandled Type...");
break;
};
}
//data
ETESTCASE m_eTestCase;
};
////////////////////////////////////////////////////////////////////////
// CAlterIndex - Class for IAlterIndex Test Cases.
//
////////////////////////////////////////////////////////////////////////
class CAlterIndex : public CSessionObject, public TCBase
{
public:
//constructors
CAlterIndex(WCHAR* pwszTestCaseName = INVALID(WCHAR*));
virtual ~CAlterIndex();
//methods
virtual BOOL Init();
virtual BOOL Terminate();
protected:
//VARIABLES...
HRESULT m_hr;
ULONG m_cMaxTableName, m_cMaxIndexName, m_cMaxColumnName;
LPOLESTR m_pwszInvalidTableChars;
LPOLESTR m_pwszInvalidTableStartingChars;
LPOLESTR m_pwszInvalidIndexChars;
LPOLESTR m_pwszInvalidIndexStartingChars;
LPOLESTR m_pwszInvalidColumnChars;
ULONG m_cPropSets;
DBPROPSET* m_rgPropSets;
BOOL m_ulIRowsetIndex;
BOOL m_ulOpenIndexSupport;
DBCOLUMNDESC* m_rgColumnDesc;
DBORDINAL m_cColumnDesc;
DBID* m_pIndexID;
DBINDEXCOLUMNDESC* m_pIndexColumnDesc;
DBORDINAL m_cIndexColumnDesc;
BOOL m_fSetOnlyDefault;
CTable * m_pNoNullTable;
//INTERFACES...
IAlterIndex* m_pIAlterIndex;
IIndexDefinition* m_pIIndexDef;
IDBSchemaRowset* m_pIDBSchemaRowset;
//METHODS...
//Wrapper for corresponding method of IAlterIndex. The table
//ID used here is m_pTableID. If you want to pass in another
//table ID (like in boundary cases), call method directly.
HRESULT AlterIndex(
DBID * pIndexID,
DBID * pNewIndexID,
BOOL fValidIndex = TRUE
);
HRESULT AlterIndex(
DBID * pTableID,
DBID * pIndexID,
DBID * pNewIndexID,
BOOL fValidIndex = TRUE
);
HRESULT GetLiteralInfo();
void SetIndexCreationProps(ETESTCASE eTestCase);
WCHAR* BuildValidName(size_t length, WCHAR* pattern);
WCHAR* BuildInvalidName(size_t length, WCHAR* pattern, WCHAR* invchars);
BOOL CheckProperty(const GUID guidPropSet, DBPROP *rgProp, HRESULT hr);
// @cmember Check whether all the columns specified appear in index
// if a IRowsetIndex could be open on the index, it goes for CheckIndex2
// otherwise tries to use IDBSchemaRowset
BOOL CheckIndex(
DBID *pTableID, // the index of the table
DBID *pIndexDBID, // the index to be checked
ULONG cPropertySets = 0, // number of property sets
DBPROPSET *rgPropertySets = NULL // the array of property sets
);
// @cmember Check whether all the columns specified appear in index
// opens an IRowsetIndex and checks everything
BOOL CheckIndex2(
DBID *pTableID, // the index of the table
DBID *pIndexDBID, // the index to be checked
ULONG cPropertySets = 0, // number of property sets
DBPROPSET *rgPropertySets = NULL // the array of property sets
);
//Read the value of a column in the indexe schema rowset
//RETURNS FALSE if the value was read and differ than the original one
BOOL GetIndexValue(
LPVOID pVariable, // [OUT] value read
BOOL *pfSet, // [OUT] if the value is set
DBBINDING *rgDBBINDING, // [IN] binding array
ULONG cColumn, // [IN] column to be read
ULONG ulDBTYPE, // [IN] type of property variant
BYTE *pData, // [IN] pointer to read DATA stru
WCHAR *lpwszMesaj // [IN] message text for error
);
//Read the value of a column in the indexe schema rowset
//RETURNS FALSE if the value was read and differ than the original one
BOOL GetIndexValueFromFirstRow(
LPVOID pVariable, // [OUT] value read
BOOL *pfSet, // [OUT] if the value is set
DBBINDING *rgDBBINDING, // [IN] binding array
ULONG cColumn, // [IN] column to be read
ULONG ulDBTYPE, // [IN] type of property variant
BYTE *pData, // [IN] pointer to read DATA stru
DBPROPID PropID, // [IN] property that is being read
ULONG cPropSets, // [IN] number of property sets
DBPROPSET *rgPropSets, // [IN] array of property sets
WCHAR *lpwszMesaj // [IN] message text for error
);
HRESULT DoesIndexExist(
DBID *pTableID, // @parm [IN] Table ID
DBID *pIndexID, // @parm [IN] Index ID
BOOL *pfExists // @parm [OUT] TRUE if index exists
);
HRESULT DoesIndexExistInIndexSchemaRowset(
DBID *pTableID, // @parm [IN] Table ID
DBID *pIndexID, // @parm [IN] Index ID
BOOL *pfExists // @parm [OUT] TRUE if index exists
);
HRESULT DoesIndexExistRowsetIndex(
DBID *pTableID, // @parm [IN] Table ID
DBID *IndexID, // @parm [IN] Index ID
BOOL *pfExists // @parm [OUT] TRUE if index exists
);
HRESULT CreateIndex(
DBID *pTableID,
DBID *pIndexID,
DBORDINAL cCols,
DBINDEXCOLUMNDESC * pIndexColumnDescs,
ULONG cPropertySets,
DBPROPSET rgPropertySets[],
DBID ** ppIndexID,
BOOL fNextIndex = FALSE,
BOOL fSetDefaultOrder = TRUE,
DBINDEX_COL_ORDER eIndexOrderDefault = DBINDEX_COL_ORDER_ASC
);
HRESULT CreateAlterableIndex(
DBID *pTableID,
DBID *pIndexID,
DBORDINAL cCols,
DBINDEXCOLUMNDESC * pIndexColumnDescs,
ULONG cPropertySets,
DBPROPSET rgPropertySets[],
DBID ** ppIndexID,
BOOL fNextIndex = FALSE,
BOOL fSetDefaultOrder = TRUE,
DBINDEX_COL_ORDER eIndexOrderDefault = DBINDEX_COL_ORDER_ASC
);
BOOL IncrementIndex(
DBORDINAL cCols,
ULONG * pIndexCols,
DBORDINAL cColumnDesc
);
BOOL FindRow(
IRowset* pIRowset,
HACCESSOR hAccessor,
LPBYTE pData,
DBCOUNTITEM cBindings,
DBBINDING * pBindings,
DBLENGTH ulRowSize,
HROW * phRow,
ULONG * pulRowNum = NULL
);
void VerifyNulls(
HRESULT hr,
CTable * pTable,
DBID * pIndexID,
ULONG ulIndexNullVal,
DBORDINAL cIndexCols,
DBINDEXCOLUMNDESC * pIndexColDesc
);
void VerifyUnique
(
HRESULT hr,
CTable * pTable,
DBID * pIndexID,
VARIANT_BOOL vbValue,
DBORDINAL cIndexCols,
DBINDEXCOLUMNDESC * pIndexColDesc
);
void VerifyPrimaryKey
(
HRESULT hr,
CTable * pTable,
DBID * pIndexID,
VARIANT_BOOL vbValue,
DBORDINAL cIndexCols,
DBINDEXCOLUMNDESC * pIndexColDesc
);
void VerifyNullCollation
(
HRESULT hr,
CTable * pTable,
DBID * pIndexID,
ULONG ulIndexNullVal,
DBORDINAL cIndexCols,
DBINDEXCOLUMNDESC * pIndexColDesc
);
BOOL GetQualifierNames(
IUnknown * pSessionIUnknown,// [in] IUnknown off session object
LPWSTR pwszTableName, // [in] the name of the table
LPWSTR *ppwszCatalogName, // [out] catalog name
LPWSTR *ppwszSchemaName // [out] schema name
);
HRESULT CleanUpIndex(
DBID *pTableID,
DBID **ppIndexID,
DBINDEXCOLUMNDESC * pIndexColumnDescs,
ULONG * pcPropertySets,
DBPROPSET ** ppPropertySets
);
void FreeIndexColumnDesc(DBORDINAL * pcColDesc, DBINDEXCOLUMNDESC ** ppIndexColumnDesc, BOOL fFreeBuf);
//Thread Methods
static ULONG WINAPI Thread_VerifyAlterIndex(LPVOID pv);
};
//----------------------------------------------------------------------
// CAlterIndex::CAlterIndex
//
CAlterIndex::CAlterIndex(WCHAR * wstrTestCaseName) : CSessionObject(wstrTestCaseName)
{
m_ulIRowsetIndex = OIS_NONE;
m_ulOpenIndexSupport= OIS_NONE;
m_cColumnDesc = 0;
m_rgColumnDesc = NULL;
m_cPropSets = 0;
m_rgPropSets = NULL;
m_pIndexID = NULL;
m_pwszInvalidTableChars = NULL;
m_pwszInvalidTableStartingChars = NULL;
m_pwszInvalidIndexChars = NULL;
m_pwszInvalidIndexStartingChars = NULL;
m_pwszInvalidColumnChars = NULL;
m_pIAlterIndex = NULL;
m_pIIndexDef = NULL;
m_pIDBSchemaRowset = NULL;
m_pIndexColumnDesc = NULL;
m_cIndexColumnDesc = 0;
m_fSetOnlyDefault = FALSE;
m_pNoNullTable = NULL;
}
//----------------------------------------------------------------------
// CAlterIndex::~CAlterIndex
//
CAlterIndex::~CAlterIndex(void)
{
if (m_pNoNullTable)
{
CHECK(m_pNoNullTable->DropTable(), S_OK);
SAFE_DELETE(m_pNoNullTable);
}
}
//----------------------------------------------------------------------
// CAlterIndex::Init
//
BOOL CAlterIndex::Init()
{
TBEGIN
HRESULT hr;
ULONG i=0;
DBID *pIndexID = NULL;
CList <WCHAR*, WCHAR*> ListNativeTemp;
CList <DBTYPE, DBTYPE> ListDataTypes;
ULONG cSchema = 0;
DBCOUNTITEM iRow = 0;
ULONG* prgRestrictions = NULL;
GUID* prgSchemas = NULL;
IRowsetIndex* pIRowsetIndex = NULL;
LPWSTR pwszProviderFileName = NULL;
// These get init'd in the constructor, but if test is run twice constructor
// isn't called again...
m_pIndexColumnDesc = NULL;
m_cIndexColumnDesc = 0;
TESTC(CSessionObject::Init())
SetDataSourceObject(m_pThisTestModule->m_pIUnknown, TRUE);
SetDBSession(m_pThisTestModule->m_pIUnknown2);
GetLiteralInfo();
TESTC(VerifyInterface(GetModInfo()->GetThisTestModule()->m_pIUnknown2,
IID_IAlterIndex, SESSION_INTERFACE, (IUnknown**)&m_pIAlterIndex))
//If IAlterIndex is supported, IIndexDefinition also has
//to be supported.
TESTC(VerifyInterface(m_pIAlterIndex, IID_IIndexDefinition,
SESSION_INTERFACE, (IUnknown**)&m_pIIndexDef))
//Check if IDBSchemaRowset is supported.
if(!VerifyInterface(m_pIAlterIndex, IID_IDBSchemaRowset,
SESSION_INTERFACE, (IUnknown**)&m_pIDBSchemaRowset))
{
TESTC(!m_pIDBSchemaRowset)
odtLog<<L"INFO: IDBSchemaRowset is not supported.\n";
}
if(m_pIDBSchemaRowset)
{
//Check whether it supports INDEXES Schema Rowset and its restrictions.
//If not then might as well release m_pIDBSchemaRowset
//to indicate it.
TESTC_(m_hr = m_pIDBSchemaRowset->GetSchemas(&cSchema, &prgSchemas, &prgRestrictions), S_OK)
for(i=0; i<cSchema; i++)
{
if(prgSchemas[i] == DBSCHEMA_INDEXES)
break;
}
if( (i >= cSchema)
|| !(prgRestrictions[i] & 0x4)
|| !(prgRestrictions[i] & 0x10))
{
SAFE_RELEASE(m_pIDBSchemaRowset);
odtLog<<L"INFO: INDEXES Schema Rowset or table and index restrictions are not supported.\n";
}
}
// create a table and get info about all the data types
GetModInfo()->UseITableDefinition(TRUE);
// We have to create a table with no nulls or some index properties can't be set.
// Many providers require no nulls for the unique index column, and there is a
// separate DBPROP_INDEX_NULLS we want to test. We can add null values later.
// But if we want to have no nulls but insert nulls later we have to fool privlib
m_pTable = new CTable(m_pThisTestModule->m_pIUnknown2, (LPWSTR)gwszModuleName, USENULLS);
TESTC(NULL != m_pTable);
// To test PRIMARYKEY prop we need a table that doesn't allow nulls in columns
m_pNoNullTable = new CTable(m_pThisTestModule->m_pIUnknown2, (LPWSTR)gwszModuleName, NONULLS);
TESTC(NULL != m_pNoNullTable);
// get the provider types list
m_pTable->CreateColInfo(ListNativeTemp, ListDataTypes, ALLTYPES);
// get the column description array
TESTC_(m_pTable->BuildColumnDescs(&m_rgColumnDesc), S_OK);
m_cColumnDesc=m_pTable->CountColumnsOnTable();
m_pTable->SetColumnDesc(m_rgColumnDesc, m_cColumnDesc);
m_pTable->SetBuildColumnDesc(FALSE);
// Create table with no rows but nullable columns
TESTC(SUCCEEDED(m_hr = m_pTable->CreateTable(0, 0)));
// Create the no-null table with no index
TESTC(SUCCEEDED(m_hr = m_pNoNullTable->CreateTable(MIN_TABLE_ROWS, 0)));
if (GetModInfo()->GetFileName())
{
// If running with ini file we don't get to specify table props (NONULLS)
// so make sure they're what we need. The problem is there's no good way to
// do this. We want nullable columns but no nulls in the table. NONULLS makes
// non-nullable columns with no nulls. USENULLS makes NULLABLE columns and uses
// nulls. At this time just skip.
TESTC_PROVIDER(FALSE);
}
else
{
// Change the NONULLS flag to prevent nulls being inserted into table
m_pTable->SetNull(NONULLS);
// Insert as many rows as we want. The table may already have rows if using ini file
for (iRow = m_pTable->GetNextRowNumber(); iRow <= MIN_TABLE_ROWS; iRow++)
{
TESTC_(m_pTable->Insert(iRow),S_OK);
}
}
// Initialize pIndexColumnDesc
SAFE_ALLOC(m_pIndexColumnDesc, DBINDEXCOLUMNDESC, m_cColumnDesc);
memset(m_pIndexColumnDesc, 0, (size_t)(sizeof(DBINDEXCOLUMNDESC)*m_cColumnDesc));
//The INIT will vary depending on type of Test Case. Different
//cases will differ in the type of Index being created.
// Set properties needed for index creation
SetIndexCreationProps(m_eTestCase);
// Create index with required props and cols. We'll skip if provider
// can't support the number of cols or prop requested.
TESTC_PROVIDER(S_OK == CreateIndex(&(m_pTable->GetTableID()), NULL, m_cIndexColumnDesc,
m_pIndexColumnDesc, m_cPropSets, m_rgPropSets, &m_pIndexID));
// We should have created an index
TESTC(m_pIndexID != NULL);
//Check if IRowsetIndex is supported. Set m_ulIRowsetIndex.
//Providers can support separate indexes, integrated indexes, or both.
m_ulIRowsetIndex = OIS_NONE;
m_ulOpenIndexSupport = OIS_NONE;
// Try to open a rowset with integrated index
hr = m_pIOpenRowset->OpenRowset(NULL, &(m_pTable->GetTableID()),
m_pIndexID, IID_IRowsetIndex, 0, NULL, (IUnknown**)
&pIRowsetIndex);
// Release integrated index/table rowset
SAFE_RELEASE(pIRowsetIndex);
// Provider supports all -> S_OK
// No IRowsetIndex support -> E_NOINTERFACE
// No open index support -> DB_E_NOINDEX
TEST3C_(hr, S_OK, DB_E_NOINDEX, E_NOINTERFACE);
if (S_OK == hr)
{
m_ulIRowsetIndex |= OIS_INTEGRATED;
m_ulOpenIndexSupport|= OIS_INTEGRATED;
}
else if (E_NOINTERFACE == hr)
{
IRowset * pIRowset = NULL;
hr = m_pIOpenRowset->OpenRowset(NULL, &(m_pTable->GetTableID()),
m_pIndexID, IID_IRowset, 0, NULL, (IUnknown**)
&pIRowset);
SAFE_RELEASE(pIRowset);
if (S_OK == hr)
m_ulOpenIndexSupport|= OIS_INTEGRATED;
}
// Try to open a rowset with separate index
hr = m_pIOpenRowset->OpenRowset(NULL, NULL,
m_pIndexID, IID_IRowsetIndex, 0, NULL, (IUnknown**)
&pIRowsetIndex);
SAFE_RELEASE(pIRowsetIndex);
TEST3C_(hr, S_OK, DB_E_NOINDEX, E_NOINTERFACE);
if (S_OK == hr)
{
m_ulIRowsetIndex |= OIS_ROWSET;
m_ulOpenIndexSupport|= OIS_ROWSET;
}
else if (E_NOINTERFACE == hr)
{
IRowset * pIRowset = NULL;
hr = m_pIOpenRowset->OpenRowset(NULL, NULL,
m_pIndexID, IID_IRowset, 0, NULL, (IUnknown**)
&pIRowset);
SAFE_RELEASE(pIRowset);
if (S_OK == hr)
m_ulOpenIndexSupport|= OIS_ROWSET;
}
// Determine whether provider only supports setting props to default (current)
// value via AlterIndex.
m_fSetOnlyDefault = FALSE;
if (GetProperty(DBPROP_PROVIDERFILENAME, DBPROPSET_DATASOURCEINFO,
m_pThisTestModule->m_pIUnknown, &pwszProviderFileName) &&
COMPARE(pwszProviderFileName != NULL, TRUE))
{
for (i=0; i < NUMELEM(ProviderSupportsDefaultOnly); i++)
{
if (!wcscmp(pwszProviderFileName, ProviderSupportsDefaultOnly[i]))
m_fSetOnlyDefault = TRUE;
}
}
CLEANUP:
if(pIndexID)
ReleaseDBID(pIndexID);
SAFE_FREE(pwszProviderFileName);
SAFE_FREE(prgSchemas);
SAFE_FREE(prgRestrictions);
SAFE_RELEASE(pIRowsetIndex);
TRETURN
} //Init
//----------------------------------------------------------------------
// CAlterIndex::Terminate
//
BOOL CAlterIndex::Terminate()
{
m_pTable->SetColumnDesc(NULL);
ReleaseColumnDesc(m_rgColumnDesc, m_cColumnDesc);
if (m_pTable)
{
m_pTable->DropTable();
delete m_pTable;
m_pTable = NULL;
}
if(m_cPropSets && m_rgPropSets)
FreeProperties(&m_cPropSets, &m_rgPropSets);
if(m_pIndexID)
{
ReleaseDBID(m_pIndexID); //Also frees the DBID memory.
m_pIndexID = NULL;
}
SAFE_FREE(m_pIndexColumnDesc);
SAFE_FREE(m_pwszInvalidTableChars);
SAFE_FREE(m_pwszInvalidTableStartingChars);
SAFE_FREE(m_pwszInvalidIndexChars);
SAFE_FREE(m_pwszInvalidIndexStartingChars);
SAFE_FREE(m_pwszInvalidColumnChars);
SAFE_RELEASE(m_pIAlterIndex);
SAFE_RELEASE(m_pIOpenRowset);
SAFE_RELEASE(m_pIIndexDef);
SAFE_RELEASE(m_pIDBSchemaRowset);
ReleaseDBSession();
ReleaseDataSourceObject();
return CSessionObject::Terminate();
} //Terminate
//-------------------------------------------------------------------------
// CAlterIndex::AlterIndex
// Wrapper for corresponding method of IAlterIndex.
//
HRESULT CAlterIndex::AlterIndex(DBID* pIndexID, DBID* pNewIndexID, BOOL fValidIndex)
{
return AlterIndex(&(m_pTable->GetTableID()), pIndexID, pNewIndexID, fValidIndex);
}
//-------------------------------------------------------------------------
// CAlterIndex::AlterIndex
// Wrapper for corresponding method of IAlterIndex.
//
HRESULT CAlterIndex::AlterIndex(DBID * pTableID, DBID* pIndexID, DBID* pNewIndexID, BOOL fValidIndex)
{
HRESULT hr = E_FAIL;
BOOL fExists = FALSE;
BOOL fNewIndex = TRUE;
if(!m_pIAlterIndex)
return E_FAIL;
hr = m_pIAlterIndex->AlterIndex(pTableID, pIndexID,
pNewIndexID, m_cPropSets, m_rgPropSets);
// See if this is a new index being created
if ((pIndexID && !pNewIndexID) ||
(pIndexID == pNewIndexID) ||
CompareDBID(*pIndexID, *pNewIndexID, m_pThisTestModule->m_pIUnknown))
fNewIndex = FALSE;
// If pNewIndexID is the same as pIndexID or NULL then the index
// is unchanged. But since we always verify on pNewIndex ID we
// have to set it.
if (!pNewIndexID)
pNewIndexID = pIndexID;
// If AlterIndex was successful or this was a duplicate index make sure
// the index actually exists
if(hr==S_OK || hr==DB_S_ERRORSOCCURRED || hr == DB_E_DUPLICATEINDEXID)
{
if(S_OK == DoesIndexExist(pTableID,
pNewIndexID, &fExists) && COMPARE(fExists, TRUE))
{
// Check values in index. For DB_E_DUPLICATEINDEXID the props
// should remain as before.
// TODO: Retain previous props and pass to this function for verification
// when DB_E_DUPLICATEINDEXID is returned
COMPARE(CheckIndex(pTableID, pNewIndexID,
(SUCCEEDED(hr)) ? m_cPropSets : 0, m_rgPropSets), TRUE);
}
// We were successful, any old index must not exist
if(SUCCEEDED(hr) && fNewIndex && S_OK == DoesIndexExist(pTableID,
pIndexID, &fExists))
COMPARE(fExists, FALSE);
}
else
{
// An error occurred, any new index must not exist
if(fNewIndex && S_OK == DoesIndexExist(pTableID,
pNewIndexID, &fExists))
COMPARE(fExists, FALSE);
// But the previous index should always still exist if there was one
if(fValidIndex && pIndexID && S_OK == DoesIndexExist(pTableID,
pIndexID, &fExists) && COMPARE(fExists, TRUE))
{
// Check values in index.
// TODO: Retain previous props and pass to this function for verification
// when an error is returned
COMPARE(CheckIndex(pTableID, pIndexID,
(SUCCEEDED(hr)) ? m_cPropSets : 0, m_rgPropSets), TRUE);
}
}
// If S_OK is returned all props must have DBPROPSTATUS_OK.
// If DB_E/S_ERRORSOCCURRED was returned one of the props must have status set
COMPARE(VerifyProperties(hr, m_cPropSets, m_rgPropSets), TRUE);
return hr;
} //AlterIndex
BOOL CAlterIndex::IncrementIndex(DBORDINAL cCols, ULONG * pIndexCols, DBORDINAL cColumnDesc)
{
if (!cCols)
return FALSE;
ASSERT(*pIndexCols < cColumnDesc);
if (*pIndexCols < cColumnDesc)
{
(*pIndexCols)++;
if (*pIndexCols == cColumnDesc)
{
*pIndexCols = 0;
return IncrementIndex(--cCols, ++pIndexCols, cColumnDesc);
}
return TRUE;
}
return FALSE;
}
BOOL CAlterIndex::FindRow
(
IRowset* pIRowset,
HACCESSOR hAccessor,
LPBYTE pData,
DBCOUNTITEM cBindings,
DBBINDING * pBindings,
DBLENGTH ulRowSize,
HROW * phRow,
ULONG * pulRowNum
)
{
LPBYTE pFindData = NULL;
DBCOUNTITEM cRowsObtained = 0;
ULONG iRow = 0;
BOOL fFound = FALSE;
HRESULT hr = E_FAIL;
// Validate args
TESTC(pIRowset && pData && cBindings &&
pBindings && ulRowSize && phRow);
*phRow = DB_NULL_HROW;
SAFE_ALLOC(pFindData, BYTE, ulRowSize);
TESTC_(pIRowset->RestartPosition(NULL), S_OK);
while(S_OK == (hr = pIRowset->GetNextRows(NULL, 0, 1, &cRowsObtained, &phRow)))
{
iRow++;
// Retrieve the data for the row
TESTC_(pIRowset->GetData(*phRow, hAccessor, pFindData), S_OK);
// See if the row matches
if (CompareBuffer(pFindData, pData, cBindings, pBindings, NULL,
TRUE, FALSE, COMPARE_ONLY))
{
// This is our row
fFound = TRUE;
break;
}
CHECK(pIRowset->ReleaseRows(1, phRow, NULL, NULL, NULL), S_OK);
*phRow = DB_NULL_HROW;
CHECK(ReleaseInputBindingsMemory(cBindings, pBindings, pFindData, FALSE), S_OK);
}
// S_OK - We found the row, no need to search farther
// DB_S_ENDOFROWSET - Didn't find our row
TEST2C_(hr, S_OK, DB_S_ENDOFROWSET);
CLEANUP:
CHECK(ReleaseInputBindingsMemory(cBindings, pBindings, pFindData, TRUE), S_OK);
if (pulRowNum)
*pulRowNum = iRow;
return fFound;
}
//-------------------------------------------------------------------------
// CAlterIndex::CreateAlterableIndex
// Create an index that can be altered to the desire props.
//
HRESULT CAlterIndex::CreateAlterableIndex(
DBID *pTableID,
DBID *pIndexID,
DBORDINAL cCols,
DBINDEXCOLUMNDESC * pIndexColumnDescs,
ULONG cPropertySets,
DBPROPSET rgPropertySets[],
DBID ** ppIndexID,
BOOL fNextIndex,
BOOL fSetDefaultOrder,
DBINDEX_COL_ORDER eIndexOrderDefault
)
{
HRESULT hr = E_FAIL;
TESTC(pTableID != NULL);
TESTC(ppIndexID != NULL);
// Create an index with the desired props so we can find the columns
// that we can later alter.
hr = CreateIndex(pTableID, pIndexID, cCols,
pIndexColumnDescs, cPropertySets, rgPropertySets, ppIndexID);
// If the provider doesn't allow setting props at AlterIndex time then
// leave the index created with props so we can alter to "default" values.
if (!m_fSetOnlyDefault)
{
// Drop and release the index that has the props set
CHECK(m_pIIndexDef->DropIndex(pTableID, *ppIndexID), S_OK);
ReleaseDBID(*ppIndexID);
// If we created an index with the desired props
if (S_OK == hr)
{
// Create an index to use that has no props set using the same columns.
TESTC_(hr = CreateIndex(pTableID, pIndexID, cCols,
pIndexColumnDescs, 0, NULL, ppIndexID), S_OK);
}
}
CLEANUP:
return hr;
}
//-------------------------------------------------------------------------
// CAlterIndex::CreateIndex
// Wrapper for corresponding method of IIndexDefinition.
//
HRESULT CAlterIndex::CreateIndex(
DBID *pTableID,
DBID *pIndexID,
DBORDINAL cCols,
DBINDEXCOLUMNDESC * pIndexColumnDescs,
ULONG cPropertySets,
DBPROPSET rgPropertySets[],
DBID ** ppIndexID,
BOOL fNextIndex,
BOOL fSetDefaultOrder,
DBINDEX_COL_ORDER eIndexOrderDefault
)
{
ULONG iCol;
BOOL * pfSetDBID = NULL;
BOOL fNewDBID = TRUE;
HRESULT hr = DB_E_ERRORSOCCURRED;
DBID * pNewIndexID = NULL;
ULONG * rgIndexCols = NULL;
SAFE_ALLOC(pfSetDBID, BOOL, cCols);
memset(pfSetDBID, 0, (size_t)(cCols*sizeof(BOOL)));
SAFE_ALLOC(rgIndexCols, ULONG, cCols);
memset(rgIndexCols, 0, (size_t)(cCols*sizeof(ULONG)));
// Set up initial conditions
// Iterate over all desired columns
for (iCol = 0; iCol < cCols; iCol++)
{
// Set the default index order if requested
if (fSetDefaultOrder)
pIndexColumnDescs[iCol].eIndexColOrder = eIndexOrderDefault;
// If no DBID was specified for the column then start with the first one
// by default (index 0, set above with memset)
if (!pIndexColumnDescs[iCol].pColumnID)
{
// Remember which ones to set
pfSetDBID[iCol] = TRUE;
}
else
{
// Find the matching index
for (; rgIndexCols[iCol] < m_cColumnDesc; rgIndexCols[iCol]++)
if (pIndexColumnDescs[iCol].pColumnID ==
&m_rgColumnDesc[rgIndexCols[iCol]].dbcid)
break;
}
}
// Increment to next possible index if requested
if (fNextIndex)
fNewDBID = IncrementIndex(cCols, rgIndexCols, m_cColumnDesc);
// While we have a new set of DBID's we haven't tried
while (fNewDBID)
{
// Set the dbid for each index column desc
for (iCol=0; iCol < cCols; iCol++)
pIndexColumnDescs[iCol].pColumnID = &m_rgColumnDesc[rgIndexCols[iCol]].dbcid;
// Now we have a set of DBID's as a candidate for an index so try to create
if (SUCCEEDED(hr = m_pIIndexDef->CreateIndex(pTableID, pIndexID,
cCols, pIndexColumnDescs, cPropertySets, rgPropertySets,
&pNewIndexID)))
{
BOOL fExists = FALSE;
SAFE_ALLOC(*ppIndexID, DBID, 1);
memset(*ppIndexID, 0, sizeof(DBID));
DuplicateDBID(*pNewIndexID, *ppIndexID);
fNewDBID = FALSE;
// Just because CreateIndex returned S_OK doesn't mean the index exists,
// so check to make sure
TESTC_(DoesIndexExist(pTableID, pNewIndexID, &fExists), S_OK);
TESTC(fExists == TRUE);
break;
}
fNewDBID = IncrementIndex(cCols, rgIndexCols, m_cColumnDesc);
}
CLEANUP:
if (pNewIndexID)
{
ReleaseDBID(pNewIndexID);
pNewIndexID = NULL;
}
SAFE_FREE(pfSetDBID);
SAFE_FREE(rgIndexCols);
return hr;
} //CreateIndex
//-------------------------------------------------------------------------
// CAlterIndex::VerifyNulls
//
// Verify table/index null handling matches expected based on setting
//
void CAlterIndex::VerifyNulls
(
HRESULT hr,
CTable * pTable,
DBID * pIndexID,
ULONG ulIndexNullVal,
DBORDINAL cIndexCols,
DBINDEXCOLUMNDESC * pIndexColDesc
)
{
HRESULT hrNullInsert = E_FAIL;
BOOL fFindInsertedNull = FALSE;
DBORDINAL cStates = 2 << (cIndexCols-1);
ULONG iState = 0;
ULONG iBind = 0;
ULONG cInsertProps = 0;
DBPROPSET * prgInsertProps = NULL;
IRowsetChange * pIRowsetChange = NULL;
IRowset * pIRowset = NULL;
HACCESSOR hAccessor = DB_NULL_HACCESSOR;
DBCOUNTITEM cBindings = 0;
DBBINDING * pBindings = NULL;
DBLENGTH ulRowSize = 0;
HROW hRow = DB_NULL_HROW;
HROW * phRow = &hRow;
LPBYTE pData = NULL;
DBORDINAL cCols = pTable->CountColumnsOnTable();
CCol TempCol;
// If we didn't set successfully, then no need to verify
if (FAILED(hr))
return;
// We have to know the table and index
TESTC(pTable != NULL);
TESTC(pIndexID != NULL);
switch(ulIndexNullVal)
{
case DBPROPVAL_IN_ALLOWNULL:
hrNullInsert = S_OK; // Inserting NULL key will succeed
fFindInsertedNull = TRUE; // We will see the NULL key with OpenRowset
break;
case DBPROPVAL_IN_DISALLOWNULL:
hrNullInsert = DB_E_INTEGRITYVIOLATION; // Inserting NULL key will fail
fFindInsertedNull = FALSE; // We will not see the NULL key with OpenRowset
break;
case DBPROPVAL_IN_IGNORENULL:
hrNullInsert = S_OK; // Inserting NULL key will succeed
fFindInsertedNull = FALSE; // We will not see the NULL key with OpenRowset
break;
case DBPROPVAL_IN_IGNOREANYNULL:
hrNullInsert = S_OK; // Inserting NULL key will succeed
fFindInsertedNull = FALSE; // We will not see the NULL key with OpenRowset
break;
default:
TESTC(FALSE);
break;
}
// Set props to allow inserts
TESTC(SetProperty(DBPROP_UPDATABILITY, DBPROPSET_ROWSET, &cInsertProps, &prgInsertProps, (void*)(DBPROPVAL_UP_INSERT | DBPROPVAL_UP_DELETE), DBTYPE_I4, DBPROPOPTIONS_REQUIRED));
// OpenRowset on table using no index requesting insert
TESTC_(m_pIOpenRowset->OpenRowset(NULL, &pTable->GetTableID(),
NULL, IID_IRowsetChange, cInsertProps, prgInsertProps, (IUnknown**)
&pIRowsetChange), S_OK);
TESTC(VerifyInterface(pIRowsetChange, IID_IRowset, ROWSET_INTERFACE, (IUnknown**)&pIRowset));
// GetAccessorAndBindings for all rows, no bookmark
TESTC_(hr = GetAccessorAndBindings(
pIRowsetChange, DBACCESSOR_ROWDATA, &hAccessor, &pBindings,
&cBindings, &ulRowSize, DBPART_VALUE |DBPART_STATUS |DBPART_LENGTH,
ALL_COLS_EXCEPTBOOKMARK, FORWARD, NO_COLS_BY_REF,
NULL, // OUT: Array of DBCOLUMNINFOs
0, // OUT: Count of DBCOULMNINFOs
NULL, //&pStringsBuffer,
DBTYPE_EMPTY,
0, NULL, NULL, NO_COLS_OWNED_BY_PROV, DBPARAMIO_NOTPARAM, BLOB_LONG),S_OK); // NO_BLOB_COLS);
// For each state
// States = 2^N, where N == numer of key columns, i.e. col is null or not null.
for (iState = 0; iState < cStates; iState++)
{
BOOL fNULLKey = FALSE;
ULONG cBitsSet = 0;
// Fill input bindings with data for new row
TESTC_(FillInputBindings(pTable,
DBACCESSOR_ROWDATA, cBindings, pBindings, &pData, pTable->GetNextRowNumber(),
0, NULL, PRIMARY), S_OK);
// Insert NULL in key field for each bit set
for(ULONG iBit = 0; iBit < cIndexCols; iBit++)
{
// If the bit is set in this state
if (iState & (1 << iBit))
{
// Find this index column in the cTable
for (iBind = 0; iBind < cBindings; iBind++)
{
// Retrieve colinfo for this column
TESTC_(pTable->GetColInfo(pBindings[iBind].iOrdinal, TempCol), S_OK);
// If the DBID's match this is the right column
if (CompareDBID(*pIndexColDesc[iBit].pColumnID,
*TempCol.GetColID(), m_pThisTestModule->m_pIUnknown))
break;
}
// Make sure we found the index col
TESTC(iBind < cBindings);
// If the column is nullable insert a NULL. Some columns aren't nullable,
// such as autoinc columns.
if (TempCol.GetNullable())
{
// Insert NULL in this (iBit) key field
STATUS_BINDING(pBindings[iBind], pData) = DBSTATUS_S_ISNULL;
cBitsSet++;
ASSERT(cBitsSet <= cIndexCols);
}
}
} // Next bit
// fNULLKey = cBitsSet == n
fNULLKey = (cIndexCols == cBitsSet);
// Attempt to insert row. If NULL key expect hrNullInsert, otherwise S_OK.
hr = pIRowsetChange->InsertRow(NULL, hAccessor, pData, NULL);
// For NULL key we can have either either DB_E_INTEGRITYVIOLATION or
// DB_E_ERRORSOCCURRED when failure is expected
if (fNULLKey && FAILED(hrNullInsert))
{
if (hr == DB_E_ERRORSOCCURRED)
{
// Status must be DBSTATUS_E_INTEGRITYVIOLATION for key columns
for(ULONG iBit = 0; iBit < cIndexCols; iBit++)
{
// If the bit is set in this state
if (iState & (1 << iBit))
{
// Find this index column in the cTable
for (iBind = 0; iBind < cBindings; iBind++)
{
// Retrieve colinfo for this column
TESTC_(pTable->GetColInfo(pBindings[iBind].iOrdinal, TempCol), S_OK);
// If the DBID's match this is the right column
if (CompareDBID(*pIndexColDesc[iBit].pColumnID,
*TempCol.GetColID(), m_pThisTestModule->m_pIUnknown))
break;
}
// Make sure we found the index col
TESTC(iBind < cBindings);
// Check the status
COMPARE(STATUS_BINDING(pBindings[iBind], pData), DBSTATUS_E_INTEGRITYVIOLATION);
}
else
// Check the status
COMPARE(STATUS_BINDING(pBindings[iBind], pData), DBSTATUS_E_UNAVAILABLE);
}
}
else
CHECK(hr, hrNullInsert);
}
else
CHECK(hr, S_OK);
// If insertion was successful
if (SUCCEEDED(hr))
{
IRowset * pIRowsetWithIndex = NULL;
IAccessor * pIAccessorIndex = NULL;
HROW hRowPos = DB_NULL_HROW;
HRESULT hrGetNextRows = S_OK;
ULONG iRow = 0;
HACCESSOR hIndexAccessor = DB_NULL_HACCESSOR;
// OpenRowset using index and find the key value expecting fFindInsertedNull.
// Note this will succeed only on providers supporting opening indexes via
// OpenRowset (i.e. Jolt).
if (m_ulOpenIndexSupport & OIS_INTEGRATED)
{
// Open the rowset with no props but using the index
TESTC_(m_pIOpenRowset->OpenRowset(NULL, &pTable->GetTableID(),
pIndexID, IID_IRowset, 0, NULL, (IUnknown**)
&pIRowsetWithIndex), S_OK);
TESTC(VerifyInterface(pIRowsetWithIndex, IID_IAccessor, ROWSET_INTERFACE, (IUnknown**)&pIAccessorIndex));
// Create an accessor off this rowset using our known bindings
TESTC_(hr = pIAccessorIndex->CreateAccessor(DBACCESSOR_ROWDATA, cBindings, pBindings,
0, &hIndexAccessor, NULL), S_OK);
// Find our inserted row
COMPARE(FindRow(pIRowsetWithIndex, hAccessor, pData, cBindings, pBindings, ulRowSize, &hRowPos, NULL), fNULLKey ? fFindInsertedNull : TRUE);
if (hRowPos != DB_NULL_HROW)
CHECK(pIRowsetWithIndex->ReleaseRows(1, &hRowPos, NULL, NULL, NULL), S_OK);
SAFE_RELEASE_ACCESSOR(pIAccessorIndex, hIndexAccessor);
SAFE_RELEASE(pIAccessorIndex);
SAFE_RELEASE(pIRowsetWithIndex);
}
else if (m_ulOpenIndexSupport & OIS_ROWSET)
{
TESTC(FALSE);
odtLog << L"Provider only supports non-integrated index, need more code.\n";
}
// Now delete the inserted row
if (COMPARE(FindRow(pIRowset, hAccessor, pData, cBindings, pBindings, ulRowSize, phRow), TRUE))
{
TESTC_(pIRowsetChange->DeleteRows(NULL, 1, &hRow, NULL), S_OK);
CHECK(pIRowset->ReleaseRows(1, phRow, NULL, NULL, NULL), S_OK);
}
}
} // Next state
CLEANUP:
// Release binding memory and pData buffer
FreeProperties(&cInsertProps, &prgInsertProps);
CHECK(ReleaseInputBindingsMemory(cBindings, pBindings, pData, TRUE), S_OK);
SAFE_RELEASE(pIRowsetChange);
SAFE_RELEASE(pIRowset);
return;
}
//-------------------------------------------------------------------------
// CAlterIndex::VerifyUnique
//
// Verify unique handling matches expected based on setting
//
void CAlterIndex::VerifyUnique
(
HRESULT hr,
CTable * pTable,
DBID * pIndexID,
VARIANT_BOOL vbValue,
DBORDINAL cIndexCols,
DBINDEXCOLUMNDESC * pIndexColDesc
)
{
HRESULT hrInsertNonUnique = E_FAIL;
BOOL fFindInserted = FALSE;
DBORDINAL cStates = 2 << (cIndexCols-1);
ULONG iState = 0;
ULONG iBind = 0;
ULONG cInsertPropSets = 0;
DBPROPSET * prgInsertPropSets= NULL;
IRowsetChange * pIRowsetChange = NULL;
IRowset * pIRowset = NULL;
IAccessor * pIAccessor = NULL;
HACCESSOR hAccessor = DB_NULL_HACCESSOR;
DBCOUNTITEM cBindings = 0;
DBBINDING * pBindings = NULL;
DBLENGTH ulRowSize = 0;
HROW hRow = DB_NULL_HROW;
HROW * phRow = &hRow;
LPBYTE pData = NULL;
DBORDINAL cCols = pTable->CountColumnsOnTable();
CCol TempCol;
// If we didn't set successfully, then no need to verify
if (FAILED(hr))
return;
// We have to know the table and index
TESTC(pTable != NULL);
TESTC(pIndexID != NULL);
switch(vbValue)
{
case VARIANT_TRUE:
hrInsertNonUnique = DB_E_INTEGRITYVIOLATION;// Inserting non unique key will fail
fFindInserted = FALSE; // We will not see the unique value with OpenRowset
break;
case VARIANT_FALSE:
hrInsertNonUnique = S_OK; // Inserting non unique key will succeed
fFindInserted = TRUE; // We will see the unique value with OpenRowset
break;
default:
TESTC(FALSE);
break;
}
// Set props to allow inserts
TESTC(SetProperty(DBPROP_UPDATABILITY, DBPROPSET_ROWSET, &cInsertPropSets, &prgInsertPropSets, (void*)(DBPROPVAL_UP_INSERT | DBPROPVAL_UP_DELETE), DBTYPE_I4, DBPROPOPTIONS_REQUIRED));
// For each state
// States = 2^N, where N == numer of key columns, i.e. col is null or not null.
for (iState = 0; iState < cStates; iState++)
{
BOOL fDupeKey = FALSE;
ULONG cBitsSet = 0;
if (!pIRowsetChange)
{
// OpenRowset on table using no index requesting insert
TESTC_(m_pIOpenRowset->OpenRowset(NULL, &pTable->GetTableID(),
NULL, IID_IRowsetChange, cInsertPropSets, prgInsertPropSets, (IUnknown**)
&pIRowsetChange), S_OK);
TESTC(VerifyInterface(pIRowsetChange, IID_IRowset, ROWSET_INTERFACE, (IUnknown**)&pIRowset));
TESTC(VerifyInterface(pIRowsetChange, IID_IAccessor, ROWSET_INTERFACE, (IUnknown**)&pIAccessor));
if (!cBindings)
{
ASSERT(pBindings == NULL);
// GetAccessorAndBindings for all rows, no bookmark
TESTC_(hr = GetAccessorAndBindings(
pIRowsetChange, DBACCESSOR_ROWDATA, &hAccessor, &pBindings,
&cBindings, &ulRowSize, DBPART_VALUE |DBPART_STATUS |DBPART_LENGTH,
ALL_COLS_EXCEPTBOOKMARK, FORWARD, NO_COLS_BY_REF,
NULL, // OUT: Array of DBCOLUMNINFOs
0, // OUT: Count of DBCOULMNINFOs
NULL, //&pStringsBuffer,
DBTYPE_EMPTY,
0, NULL, NULL, NO_COLS_OWNED_BY_PROV, DBPARAMIO_NOTPARAM, BLOB_LONG),S_OK); // NO_BLOB_COLS);
}
else
TESTC_(hr = pIAccessor->CreateAccessor(DBACCESSOR_ROWDATA, cBindings, pBindings,
0, &hAccessor, NULL), S_OK);
}
// Fill input bindings with data for new row. Since specifying PRIMARY row seed
// can result in duplicate data in a given row we use SECONDARY data.
TESTC_(FillInputBindings(pTable,
DBACCESSOR_ROWDATA, cBindings, pBindings, &pData, pTable->GetNextRowNumber(),
0, NULL, SECONDARY), S_OK);
// Insert non-unique in key field for each bit set
for(ULONG iBit = 0; iBit < cIndexCols; iBit++)
{
// If the bit is set in this state
if (iState & (1 << iBit))
{
// Find this index column in the cTable
for (iBind = 0; iBind < cBindings; iBind++)
{
// Retrieve colinfo for this column
TESTC_(pTable->GetColInfo(pBindings[iBind].iOrdinal, TempCol), S_OK);
// If the DBID's match this is the right column
if (CompareDBID(*pIndexColDesc[iBit].pColumnID,
*TempCol.GetColID(), m_pThisTestModule->m_pIUnknown))
break;
}
// Make sure we found the index col
TESTC(iBind < cBindings);
// If the column is nullable insert a NULL. Some columns aren't nullable,
// such as autoinc columns.
if (TempCol.GetUpdateable())
{
// Insert duplicate in this (iBit) key field
// This changes the data to duplicate the last row in this column
CHECK(ReleaseInputBindingsMemory(1, &pBindings[iBind], pData, FALSE), S_OK);
TESTC_(FillInputBindings(pTable,
DBACCESSOR_ROWDATA, 1, &pBindings[iBind], &pData, pTable->GetNextRowNumber()-1,
0, NULL, PRIMARY), S_OK);
cBitsSet++;
ASSERT(cBitsSet <= cIndexCols);
}
}
} // Next bit
// fDupeKey = cBitsSet == n
fDupeKey = (cIndexCols == cBitsSet);
// Attempt to insert row. If NULL key expect hrNullInsert, otherwise S_OK.
if (1)
{
CHECK(hr = pIRowsetChange->InsertRow(NULL, hAccessor, pData, NULL),
fDupeKey ? hrInsertNonUnique : S_OK);
}
// hr = E_FAIL;
// If insertion was successful
if (SUCCEEDED(hr))
{
IRowset * pIRowsetWithIndex = NULL;
IAccessor * pIAccessorIndex = NULL;
HROW hRowPos = DB_NULL_HROW;
HRESULT hrGetNextRows = S_OK;
ULONG iRow = 0;
HACCESSOR hIndexAccessor = DB_NULL_HACCESSOR;
// OpenRowset using index and find the key value expecting fFindInsertedNull.
// Note this will succeed only on providers supporting opening indexes via
// OpenRowset (i.e. Jolt).
if (m_ulOpenIndexSupport & OIS_INTEGRATED)
{
// Open the rowset with no props but using the index
TESTC_(m_pIOpenRowset->OpenRowset(NULL, &pTable->GetTableID(),
pIndexID, IID_IRowset, 0, NULL, (IUnknown**)
&pIRowsetWithIndex), S_OK);
TESTC(VerifyInterface(pIRowsetWithIndex, IID_IAccessor, ROWSET_INTERFACE, (IUnknown**)&pIAccessorIndex));
// Create an accessor off this rowset using our known bindings
TESTC_(hr = pIAccessorIndex->CreateAccessor(DBACCESSOR_ROWDATA, cBindings, pBindings,
0, &hIndexAccessor, NULL), S_OK);
// Find our inserted row
COMPARE(FindRow(pIRowsetWithIndex, hAccessor, pData, cBindings, pBindings, ulRowSize, &hRowPos, NULL), fDupeKey ? fFindInserted : TRUE);
if (hRowPos != DB_NULL_HROW)
CHECK(pIRowsetWithIndex->ReleaseRows(1, &hRowPos, NULL, NULL, NULL), S_OK);
SAFE_RELEASE_ACCESSOR(pIAccessorIndex, hIndexAccessor);
SAFE_RELEASE(pIAccessorIndex);
SAFE_RELEASE(pIRowsetWithIndex);
}
else if (m_ulOpenIndexSupport & OIS_ROWSET)
{
TESTC(FALSE);
odtLog << L"Provider only supports non-integrated index, need more code.\n";
}
// Delete the row to prevent impact on other variations
// Because some providers don't allow CHANGEINSERTEDROWS without a unique index
// we need to open a rowset and search through the rows ourselves to delete the
// new row.
if (COMPARE(FindRow(pIRowset, hAccessor, pData, cBindings, pBindings, ulRowSize, phRow), TRUE))
{
TESTC_(pIRowsetChange->DeleteRows(NULL, 1, &hRow, NULL), S_OK);
CHECK(pIRowset->ReleaseRows(1, phRow, NULL, NULL, NULL), S_OK);
}
}
CHECK(ReleaseInputBindingsMemory(cBindings, pBindings, pData, FALSE), S_OK);
} // Next state
CLEANUP:
// Release binding memory and pData buffer
FreeProperties(&cInsertPropSets, &prgInsertPropSets);
CHECK(ReleaseInputBindingsMemory(cBindings, pBindings, pData, TRUE), S_OK);
SAFE_FREE(pBindings);
SAFE_RELEASE_ACCESSOR(pIAccessor, hAccessor);
SAFE_RELEASE(pIAccessor);
SAFE_RELEASE(pIRowsetChange);
SAFE_RELEASE(pIRowset);
return;
}
//-------------------------------------------------------------------------
// CAlterIndex::VerifyPrimaryKey
//
// Verify unique handling matches expected based on setting
//
void CAlterIndex::VerifyPrimaryKey
(
HRESULT hr,
CTable * pTable,
DBID * pIndexID,
VARIANT_BOOL vbValue,
DBORDINAL cIndexCols,
DBINDEXCOLUMNDESC * pIndexColDesc
)
{
// Primary keys are always unique
VerifyUnique(hr, pTable, pIndexID, vbValue, cIndexCols, pIndexColDesc);
// They also disallow nulls
if (vbValue == VARIANT_TRUE)
VerifyNulls(hr, pTable, pIndexID, DBPROPVAL_IN_DISALLOWNULL, cIndexCols, pIndexColDesc);
else
VerifyNulls(hr, pTable, pIndexID, DBPROPVAL_IN_ALLOWNULL, cIndexCols, pIndexColDesc);
}
//-------------------------------------------------------------------------
// CAlterIndex::VerifyNullCollation
//
// Verify table/index null handling matches expected based on setting
//
void CAlterIndex::VerifyNullCollation
(
HRESULT hr,
CTable * pTable,
DBID * pIndexID,
ULONG ulIndexNullVal,
DBORDINAL cIndexCols,
DBINDEXCOLUMNDESC * pIndexColDesc
)
{
BOOL fFindNullAtEnd = FALSE;
ULONG iBit = 0;
ULONG iState = 0;
ULONG iBind = 0;
ULONG cInsertProps = 0;
DBPROPSET * prgInsertProps = NULL;
IRowsetChange * pIRowsetChange = NULL;
IRowset * pIRowset = NULL;
HACCESSOR hAccessor = DB_NULL_HACCESSOR;
DBCOUNTITEM cBindings = 0;
DBBINDING * pBindings = NULL;
DBLENGTH ulRowSize = 0;
HROW hRow = DB_NULL_HROW;
HROW * phRow = &hRow;
LPBYTE pData = NULL;
BOOL fNULLKey = FALSE;
ULONG cBitsSet = 0;
DBORDINAL cCols;
CCol TempCol;
DBINDEX_COL_ORDER eCollationFirstKey;
// If we didn't set successfully, then no need to verify
if (FAILED(hr))
return;
// We have to know the table and index
TESTC(pTable != NULL);
TESTC(pIndexID != NULL);
TESTC(pIndexColDesc != NULL);
cCols = pTable->CountColumnsOnTable();
eCollationFirstKey = pIndexColDesc[0].eIndexColOrder;
switch(ulIndexNullVal)
{
case DBPROPVAL_NC_END:
fFindNullAtEnd = TRUE; // We will see the NULL key at the end of the rowset
break;
case DBPROPVAL_NC_START:
fFindNullAtEnd = FALSE; // We will see the NULL key at the start of the rowset
break;
case DBPROPVAL_NC_HIGH:
if (eCollationFirstKey == DBINDEX_COL_ORDER_ASC)
fFindNullAtEnd = TRUE; // We will see the NULL key at the end of the rowset
else
fFindNullAtEnd = FALSE; // We will see the NULL key at the start of the rowset
break;
case DBPROPVAL_NC_LOW:
if (eCollationFirstKey == DBINDEX_COL_ORDER_DESC)
fFindNullAtEnd = TRUE; // We will see the NULL key at the end of the rowset
else
fFindNullAtEnd = FALSE; // We will see the NULL key at the start of the rowset
break;
default:
TESTC(FALSE);
break;
}
// Set props to allow inserts
TESTC(SetProperty(DBPROP_UPDATABILITY, DBPROPSET_ROWSET, &cInsertProps, &prgInsertProps, (void*)(DBPROPVAL_UP_INSERT | DBPROPVAL_UP_DELETE), DBTYPE_I4, DBPROPOPTIONS_REQUIRED));
// OpenRowset on table using no index requesting insert
TESTC_(m_pIOpenRowset->OpenRowset(NULL, &pTable->GetTableID(),
NULL, IID_IRowsetChange, cInsertProps, prgInsertProps, (IUnknown**)
&pIRowsetChange), S_OK);
TESTC(VerifyInterface(pIRowsetChange, IID_IRowset, ROWSET_INTERFACE, (IUnknown**)&pIRowset));
// GetAccessorAndBindings for all rows, no bookmark
TESTC_(hr = GetAccessorAndBindings(
pIRowsetChange, DBACCESSOR_ROWDATA, &hAccessor, &pBindings,
&cBindings, &ulRowSize, DBPART_VALUE |DBPART_STATUS |DBPART_LENGTH,
ALL_COLS_EXCEPTBOOKMARK, FORWARD, NO_COLS_BY_REF,
NULL, // OUT: Array of DBCOLUMNINFOs
0, // OUT: Count of DBCOULMNINFOs
NULL, //&pStringsBuffer,
DBTYPE_EMPTY,
0, NULL, NULL, NO_COLS_OWNED_BY_PROV, DBPARAMIO_NOTPARAM, BLOB_LONG),S_OK); // NO_BLOB_COLS);
// For each state
// States = 2^N, where N == numer of key columns, i.e. col is null or not null.
// The problem here is that we end up inserting keys where for example the first key part
// is non-null and the next is null, then we have to validate where these show up in the
// rowset based on data in the first column and index null collation in the second key
// column. At this point I don't intend to test multipart null collation inserts the
// second or greater key value appropriately, it's just too much work for the gain.
iState = ~0; // All bits set
// Fill input bindings with data for new row
TESTC_(FillInputBindings(pTable,
DBACCESSOR_ROWDATA, cBindings, pBindings, &pData, pTable->GetNextRowNumber(),
0, NULL, PRIMARY), S_OK);
// Insert NULL in key field for each bit set
for(iBit = 0; iBit < cIndexCols; iBit++)
{
// If the bit is set in this state
if (iState & (1 << iBit))
{
// Find this index column in the cTable
for (iBind = 0; iBind < cBindings; iBind++)
{
// Retrieve colinfo for this column
TESTC_(pTable->GetColInfo(pBindings[iBind].iOrdinal, TempCol), S_OK);
// If the DBID's match this is the right column
if (CompareDBID(*pIndexColDesc[iBit].pColumnID,
*TempCol.GetColID(), m_pThisTestModule->m_pIUnknown))
break;
}
// Make sure we found the index col
TESTC(iBind < cBindings);
// If the column is nullable insert a NULL. Some columns aren't nullable,
// such as autoinc columns.
if (TempCol.GetNullable())
{
// Insert NULL in this (iBit) key field
STATUS_BINDING(pBindings[iBind], pData) = DBSTATUS_S_ISNULL;
cBitsSet++;
ASSERT(cBitsSet <= cIndexCols);
}
}
} // Next bit
// fNULLKey = cBitsSet == n
fNULLKey = (cIndexCols == cBitsSet);
// Attempt to insert row.
CHECK(hr = pIRowsetChange->InsertRow(NULL, hAccessor, pData, NULL), S_OK);
// If insertion was successful
if (SUCCEEDED(hr))
{
IRowset * pIRowsetWithIndex = NULL;
IAccessor * pIAccessorIndex = NULL;
HROW hRowPos = DB_NULL_HROW;
HRESULT hrGetNextRows = S_OK;
ULONG iRow = 0;
HACCESSOR hIndexAccessor = DB_NULL_HACCESSOR;
// OpenRowset using index and find the key value expecting proper location.
// Note this will succeed only on providers supporting opening indexes via
// OpenRowset (i.e. Jolt).
if (m_ulOpenIndexSupport & OIS_INTEGRATED)
{
// Open the rowset with no props but using the index
TESTC_(m_pIOpenRowset->OpenRowset(NULL, &pTable->GetTableID(),
pIndexID, IID_IRowset, 0, NULL, (IUnknown**)
&pIRowsetWithIndex), S_OK);
TESTC(VerifyInterface(pIRowsetWithIndex, IID_IAccessor, ROWSET_INTERFACE, (IUnknown**)&pIAccessorIndex));
// Create an accessor off this rowset using our known bindings
TESTC_(hr = pIAccessorIndex->CreateAccessor(DBACCESSOR_ROWDATA, cBindings, pBindings,
0, &hIndexAccessor, NULL), S_OK);
// Find our inserted row
if (COMPARE(FindRow(pIRowsetWithIndex, hAccessor, pData, cBindings, pBindings, ulRowSize, phRow, &iRow), TRUE))
{
// Release the row handle we got with FindRow
CHECK(pIRowsetWithIndex->ReleaseRows(1, phRow, NULL, NULL, NULL), S_OK);
*phRow = DB_NULL_HROW;
// See if the row came back in the right spot
if (fFindNullAtEnd)
// Must be the last row in the table
COMPARE(iRow, pTable->CountRowsOnTable());
else
// Otherwise, must be the first row
COMPARE(iRow, 1);
}
SAFE_RELEASE_ACCESSOR(pIAccessorIndex, hIndexAccessor);
SAFE_RELEASE(pIAccessorIndex);
SAFE_RELEASE(pIRowsetWithIndex);
}
else if (m_ulOpenIndexSupport & OIS_ROWSET)
{
TESTC(FALSE);
odtLog << L"Provider only supports non-integrated index, need more code.\n";
}
if (COMPARE(FindRow(pIRowset, hAccessor, pData, cBindings, pBindings, ulRowSize, phRow), TRUE))
{
TESTC_(pIRowsetChange->DeleteRows(NULL, 1, &hRow, NULL), S_OK);
CHECK(pIRowset->ReleaseRows(1, phRow, NULL, NULL, NULL), S_OK);
}
}
CLEANUP:
// Release binding memory and pData buffer
FreeProperties(&cInsertProps, &prgInsertProps);
CHECK(ReleaseInputBindingsMemory(cBindings, pBindings, pData, TRUE), S_OK);
SAFE_RELEASE(pIRowsetChange);
SAFE_RELEASE(pIRowset);
return;
}
//-------------------------------------------------------------------------
// CAlterIndex::SetIndexCreationProps
//
void CAlterIndex::SetIndexCreationProps(ETESTCASE eTestCase)
{
// We assume no props are set at this point
ASSERT(!m_cPropSets);
switch(eTestCase)
{
//Create Index with only one column and no props.
case TC_SingleColNoProps:
case TC_PropSingCol:
{
m_cIndexColumnDesc = 1;
break;
}
//Create Index with only one column and some props.
case TC_SingleColProps:
{
m_cIndexColumnDesc = 1;
//Set one Index prop (required)
SetProperty(DBPROP_INDEX_UNIQUE, DBPROPSET_INDEX, &m_cPropSets, &m_rgPropSets, (void*)VARIANT_TRUE, DBTYPE_BOOL, DBPROPOPTIONS_REQUIRED);
break;
}
//Create Index with multiple columns and no props.
case TC_MultipleColsNoProps:
case TC_PropMultCol:
{
m_cIndexColumnDesc = MAX_INDEX_COLS;
break;
}
//Create Index with multiple columns some props.
case TC_MultipleColsProps:
{
m_cIndexColumnDesc = MAX_INDEX_COLS;
//Set one Index prop (required)
SetProperty(DBPROP_INDEX_UNIQUE, DBPROPSET_INDEX, &m_cPropSets, &m_rgPropSets, (void*)VARIANT_TRUE, DBTYPE_BOOL, DBPROPOPTIONS_REQUIRED);
break;
}
default:
ASSERT(!L"Unhandled Type...");
break;
};
}
ULONG CAlterIndex::Thread_VerifyAlterIndex(void* pv)
{
THREAD_BEGIN
//Thread Stack Variables
IAlterIndex * pIAlterIndex = (IAlterIndex *)THREAD_FUNC;
DBID * pTableID = (DBID *)THREAD_ARG1;
DBID * pIndexID = (DBID *)THREAD_ARG2;
DBID * pNewID = (DBID *)THREAD_ARG3;
HRESULT * pHR = (HRESULT *)THREAD_ARG4;
ULONG cPropSets = (ULONG)(ULONG_PTR)THREAD_ARG5;
DBPROPSET * pPropSets = (DBPROPSET *)THREAD_ARG6;
ASSERT(pIAlterIndex);
ASSERT(pTableID);
ASSERT(pIndexID);
ASSERT(pNewID);
ThreadSwitch(); //Let the other thread(s) catch up
//Call AlterIndex
*pHR = pIAlterIndex->AlterIndex(pTableID, pIndexID, pNewID, cPropSets, pPropSets);
ThreadSwitch(); //Let the other thread(s) catch up
THREAD_RETURN
}
//-------------------------------------------------------------------------
// CAlterIndex::GetLiteralInfo
//
HRESULT CAlterIndex::GetLiteralInfo()
{
IDBInfo* pInterface = NULL;
const int nLiteral=3;
DBLITERAL rgLiteral[nLiteral]={DBLITERAL_TABLE_NAME, DBLITERAL_INDEX_NAME, DBLITERAL_COLUMN_NAME};
DBLITERALINFO* rgLiteralInfo = NULL;
ULONG cLiteralInfo, i;
OLECHAR* pCharBuffer = NULL;
IGetDataSource* pIGetDataSource=NULL; // IGetDataSource interface pointer
if(!VerifyInterface(m_pIOpenRowset, IID_IGetDataSource, SESSION_INTERFACE, (IUnknown**)&pIGetDataSource))
return E_FAIL;
m_hr=pIGetDataSource->GetDataSource(IID_IDBInfo,(IUnknown**)&pInterface);
SAFE_RELEASE(pIGetDataSource);
TESTC_(m_hr = pInterface->GetLiteralInfo( nLiteral, rgLiteral, &cLiteralInfo,
&rgLiteralInfo, &pCharBuffer), S_OK);
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;
SAFE_FREE(m_pwszInvalidTableChars);
m_pwszInvalidTableChars = wcsDuplicate(rgLiteralInfo[i].pwszInvalidChars?
rgLiteralInfo[i].pwszInvalidChars: L"");
SAFE_FREE(m_pwszInvalidTableStartingChars);
m_pwszInvalidTableStartingChars = wcsDuplicate(rgLiteralInfo[i].pwszInvalidStartingChars?
rgLiteralInfo[i].pwszInvalidStartingChars: L"");
break;
case DBLITERAL_INDEX_NAME:
m_cMaxIndexName = rgLiteralInfo[i].cchMaxLen;
SAFE_FREE(m_pwszInvalidIndexChars);
m_pwszInvalidIndexChars = wcsDuplicate(rgLiteralInfo[i].pwszInvalidChars?
rgLiteralInfo[i].pwszInvalidChars: L"");
SAFE_FREE(m_pwszInvalidIndexStartingChars);
m_pwszInvalidIndexStartingChars = wcsDuplicate(rgLiteralInfo[i].pwszInvalidStartingChars?
rgLiteralInfo[i].pwszInvalidStartingChars: L"");
break;
case DBLITERAL_COLUMN_NAME:
// get the maximum size of a valid column name and the invalid chars for a table name
m_cMaxColumnName = rgLiteralInfo[i].cchMaxLen;
SAFE_FREE(m_pwszInvalidColumnChars);
m_pwszInvalidColumnChars = wcsDuplicate(rgLiteralInfo[i].pwszInvalidChars?
rgLiteralInfo[i].pwszInvalidChars: L"");
break;
default:
break;
}
}
CLEANUP:
SAFE_RELEASE(pInterface);
SAFE_FREE(pCharBuffer);
SAFE_FREE(rgLiteralInfo);
return m_hr;
} //GetLiteralInfo
//-------------------------------------------------------------------------
// CAlterIndex::BuildValidName
// Build a valid table name of a certain length
//
WCHAR* CAlterIndex::BuildValidName(size_t length, WCHAR* pattern)
{
WCHAR* pwszBuffer;
size_t cLen = wcslen(pattern), i;
i=length+1;
SAFE_ALLOC(pwszBuffer, WCHAR, i);
memset(pwszBuffer, 0, i*sizeof(WCHAR));
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;
} //BuildValidName
//-------------------------------------------------------------------------
// CAlterIndex::BuildInvalidName
// Build an invalid table name of a certain length the pattern
// is supposed to be shorter than the string to be build.
//
WCHAR* CAlterIndex::BuildInvalidName(size_t length, WCHAR* pattern, WCHAR* invchars)
{
WCHAR* pwszBuffer;
size_t cLen = wcslen(pattern), i, cInvLen=wcslen(invchars);
SAFE_ALLOC(pwszBuffer, WCHAR, length+1);
if (length > cInvLen+cLen)
{
wcscpy(pwszBuffer, pattern);
wcscat(pwszBuffer, invchars);
}
else
{
wcscpy(pwszBuffer, L"aa");
wcsncat(pwszBuffer, invchars, length-wcslen(pwszBuffer));
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;
} //BuildInvalidName
//--------------------------------------------------------------------------
// CAlterIndex::CheckProperty
// Check the result and property status
//
BOOL CAlterIndex::CheckProperty(
const GUID guidPropertySet,// [in] property set guid (should be DBPROPSET_INDEX
DBPROP *pProp, // [in] property
HRESULT hr // [in] the result
)
{
BOOL fRes = TRUE;
BOOL fSupported;
BOOL fSettable;
if (!pProp)
return TRUE;
// general checking
if (DBPROPOPTIONS_REQUIRED == pProp->dwOptions && DBPROPSTATUS_OK != pProp->dwStatus)
fRes = CHECK(FAILED(hr), TRUE);
if (!(guidPropertySet == DBPROPSET_INDEX))
{
// 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 && !CHECK(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) && COMPARE(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:
fRes = COMPARE(fSupported != 0, TRUE);
break;
default:
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
if ( GetPropInfoType(pProp->dwPropertyID, guidPropertySet) != 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;
} //CheckProperty
//-------------------------------------------------------------------------
// CAlterIndex::CheckIndex
// Check whether all the columns specified appear in index
// and the properties are properly set
// returns TRUE - everything was set ok
// FALSE - problems
//
BOOL CAlterIndex::CheckIndex(
DBID *pTableID, // the index of the table
DBID *pIndexID, // the index to be checked
ULONG cPropertySets, // number of property sets
DBPROPSET *rgPropertySets // the array of property sets
)
{
HRESULT hr = E_FAIL;
BOOL fReturn = FALSE;
BOOL fProps = TRUE;
BOOL bIsSchemaSupported;
DBLENGTH ulRowSize = 0; // size of row
DBCOUNTITEM cDBBINDING = 0; // count of bindings
ULONG iRow = 0; // count of rows
DBCOUNTITEM cRowsObtained = 0; // number of rows returned, should be 1
ULONG cSchema = 0; // number of supported Schemas
ULONG *prgRestrictions= 0; // restrictions for each Schema
GUID *prgSchemas = NULL; // array of GUIDs
HROW hRow; // handler of rows
HROW *phRow = &hRow; // pointer to handler
IRowset *pIndexRowset = NULL; // returned rowset
DBBINDING *rgDBBINDING = NULL; // array of bindings
BYTE *pData = NULL; // pointer to data
HACCESSOR hAccessor = NULL; // accessor
BOOL *rgColPresent = NULL;
const int cRest = 5;
VARIANT rgRestrictIndexes[cRest];
ULONG i, index;
ULONG nColPresent=0;
ULONG nTABLE_NAME = 2;
ULONG nINDEX_NAME = 5;
ULONG nPRIMARY_KEY = 6;
ULONG nUNIQUE = 7;
ULONG nCLUSTERED = 8;
ULONG nTYPE = 9;
ULONG nFILL_FACTOR = 10;
ULONG nINITIAL_SIZE = 11;
ULONG nNULLS = 12;
ULONG nSORT_BOOKMARKS = 13;
ULONG nAUTO_UPDATE = 14;
ULONG nNULL_COLLATION = 15;
ULONG nORDINAL_POSITION = 16;
ULONG nCOLUMN_NAME = 17;
ULONG nCOLLATION = 20;
// column entries in index schema rowset and their presence flags
LPWSTR pwszIndexName = NULL;
BOOL fIndexName = FALSE;
LPWSTR pwszTableName = NULL;
BOOL fTableName = FALSE;
VARIANT_BOOL vbAutoUpdate;
BOOL fAutoUpdate = FALSE;
VARIANT_BOOL vbClustered;
BOOL fClustered = FALSE;
LONG lFillFactor;
BOOL fFillFactor = FALSE;
LONG lInitialSize;
BOOL fInitialSize = FALSE;
LONG lNullCollation;
BOOL fNullCollation = FALSE;
BOOL fCollation = FALSE;
LPWSTR pwszColumnName = NULL;
BOOL fColumnName = FALSE;
LONG lNulls;
BOOL fNulls = FALSE;
VARIANT_BOOL vbPrimaryKey;
BOOL fPrimaryKey = FALSE;
VARIANT_BOOL vbSortBookmarks;
BOOL fSortBookmarks = FALSE;
unsigned short usType;
BOOL fType = FALSE;
VARIANT_BOOL vbUnique;
BOOL fUnique = FALSE;
// Set restrictions
for(index=0;index<cRest;index++)
VariantInit(&rgRestrictIndexes[index]);
if (m_ulIRowsetIndex)
TESTC(CheckIndex2(pTableID, pIndexID, cPropertySets,
rgPropertySets));
if (NULL == m_pIDBSchemaRowset)
{
fReturn = TRUE;
goto CLEANUP;
}
// Check to see if the schema is supported
TESTC_(hr = m_pIDBSchemaRowset->GetSchemas(&cSchema, &prgSchemas, &prgRestrictions),S_OK);
if (DBKIND_NAME == pIndexID->eKind)
{
pwszIndexName = wcsDuplicate(pIndexID->uName.pwszName);
fIndexName = TRUE;
}
if (DBKIND_NAME == pTableID->eKind)
{
pwszTableName = wcsDuplicate(pTableID->uName.pwszName);
fTableName = TRUE;
}
// Check to see if DBSCHEMA_INDEXES is supported
for(i=0, bIsSchemaSupported=FALSE; i<cSchema && !bIsSchemaSupported;)
{
if(prgSchemas[i] == DBSCHEMA_INDEXES)
bIsSchemaSupported = TRUE;
else
i++;
}
if(!bIsSchemaSupported || !(prgRestrictions[i] & 0x4) || !(prgRestrictions[i] & 0x10))
{
odtLog << "Index Schema Rowset or the required constraints are not supported\n";
goto CLEANUP;
}
rgRestrictIndexes[2].vt = VT_BSTR;
rgRestrictIndexes[2].bstrVal = SysAllocString(pIndexID->uName.pwszName);
rgRestrictIndexes[4].vt = VT_BSTR;
rgRestrictIndexes[4].bstrVal = SysAllocString(pTableID->uName.pwszName);
TESTC_(hr = m_pIDBSchemaRowset->GetRowset(
NULL, // aggregation
DBSCHEMA_INDEXES, // REFGUID
cRest, // count of restrictions (1:types)
rgRestrictIndexes, // list of restrictions
IID_IRowset, // REFFID
0, // count of properties
NULL, // range of properties
(IUnknown**)&pIndexRowset // returned result set
),S_OK);
TESTC_(hr = GetAccessorAndBindings(
pIndexRowset, DBACCESSOR_ROWDATA, &hAccessor, &rgDBBINDING,
&cDBBINDING, &ulRowSize, DBPART_VALUE |DBPART_STATUS |DBPART_LENGTH,
ALL_COLS_EXCEPTBOOKMARK, FORWARD, NO_COLS_BY_REF,
NULL, // OUT: Array of DBCOLUMNINFOs
0, // OUT: Count of DBCOULMNINFOs
NULL, //&pStringsBuffer,
DBTYPE_EMPTY,
0, NULL),S_OK);
SAFE_ALLOC(pData, BYTE, ulRowSize); //data
// read the first row, check local data and initialize variables
// TODO: Read all the rows and verify the columns that were indexed and
// their collation, ordinal position, etc.
// Also verify integrated based on how openrowset performs.
TESTC_(hr=pIndexRowset->GetNextRows(0, 0, 1, &cRowsObtained, &phRow), S_OK);
TESTC_((long)cRowsObtained, 1);
TESTC_(hr=pIndexRowset->GetData(hRow, hAccessor, pData),S_OK);
// get the first values and verifications
fProps = fProps && GetIndexValue(&pwszIndexName, &fIndexName,
rgDBBINDING, nINDEX_NAME, DBTYPE_WSTR, pData, L"ERROR: Bad index name\n");
fProps = fProps && GetIndexValue(&pwszTableName, &fTableName,
rgDBBINDING, nTABLE_NAME, DBTYPE_WSTR, pData, L"ERROR: Bad table name\n");
if (cPropertySets > 0 && rgPropertySets)
{
fProps = fProps && GetIndexValueFromFirstRow(&vbAutoUpdate, &fAutoUpdate,
rgDBBINDING, nAUTO_UPDATE, DBTYPE_BOOL, pData, DBPROP_INDEX_AUTOUPDATE,
cPropertySets, rgPropertySets, L"ERROR: Auto update\n");
fProps = fProps && GetIndexValueFromFirstRow(&vbClustered, &fClustered,
rgDBBINDING, nCLUSTERED, DBTYPE_BOOL, pData, DBPROP_INDEX_CLUSTERED,
cPropertySets, rgPropertySets, L"ERROR: Clustered\n");
fProps = fProps && GetIndexValueFromFirstRow(&lFillFactor, &fFillFactor,
rgDBBINDING, nFILL_FACTOR, DBTYPE_I4, pData, DBPROP_INDEX_FILLFACTOR,
cPropertySets, rgPropertySets, L"ERROR: Fill factor\n");
fProps = fProps && GetIndexValueFromFirstRow(&lInitialSize, &fInitialSize,
rgDBBINDING, nINITIAL_SIZE, DBTYPE_I4, pData, DBPROP_INDEX_INITIALSIZE,
cPropertySets, rgPropertySets, L"ERROR: Initial Size\n");
fProps = fProps && GetIndexValueFromFirstRow(&lNullCollation, &fNullCollation,
rgDBBINDING, nNULL_COLLATION, DBTYPE_I4, pData, DBPROP_INDEX_NULLCOLLATION,
cPropertySets, rgPropertySets, L"ERROR: Null Collation\n");
fProps = fProps && GetIndexValueFromFirstRow(&lNulls, &fNulls,
rgDBBINDING, nNULLS, DBTYPE_I4, pData, DBPROP_INDEX_NULLS,
cPropertySets, rgPropertySets, L"ERROR: Nulls\n");
fProps = fProps && GetIndexValueFromFirstRow(&vbPrimaryKey, &fPrimaryKey,
rgDBBINDING, nPRIMARY_KEY, DBTYPE_BOOL, pData, DBPROP_INDEX_PRIMARYKEY,
cPropertySets, rgPropertySets, L"ERROR: Primary Key\n");
fProps = fProps && GetIndexValueFromFirstRow(&vbSortBookmarks, &fSortBookmarks,
rgDBBINDING, nSORT_BOOKMARKS, DBTYPE_BOOL, pData, DBPROP_INDEX_SORTBOOKMARKS,
cPropertySets, rgPropertySets, L"ERROR: SortBookmarks\n");
fProps = fProps && GetIndexValueFromFirstRow(&usType, &fType,
rgDBBINDING, nTYPE, DBTYPE_UI2, pData, DBPROP_INDEX_TYPE,
cPropertySets, rgPropertySets, L"ERROR: Type\n");
fProps = fProps && GetIndexValueFromFirstRow(&vbUnique, &fUnique,
rgDBBINDING, nUNIQUE, DBTYPE_BOOL, pData, DBPROP_INDEX_UNIQUE,
cPropertySets, rgPropertySets, L"ERROR: Unique\n");
}
TESTC_(pIndexRowset->ReleaseRows(1, &hRow, NULL, NULL, NULL), S_OK);
fReturn = fProps;
CLEANUP:
// Free the memory
SAFE_FREE(pwszIndexName);
SAFE_FREE(pwszTableName);
SAFE_FREE(rgColPresent);
SAFE_FREE(prgRestrictions);
SAFE_FREE(prgSchemas);
SAFE_FREE(pData);
SAFE_RELEASE(pIndexRowset);
SAFE_FREE(rgDBBINDING);
for(index=0;index<cRest;index++)
GCHECK(VariantClear(&(rgRestrictIndexes[index])),S_OK);
return fReturn;
} //CheckIndex
//-------------------------------------------------------------------------
// CAlterIndex::CheckIndex2
// Check whether all the columns specified appear in index
// and whether the properties are properly set
// uses IRowsetIndex
//-------------------------------------------------------------------------
BOOL CAlterIndex::CheckIndex2(
DBID *pTableID, // the index of the table
DBID *pIndexID, // the index to be checked
ULONG cPropertySets, // number of property sets
DBPROPSET *rgPropertySets // the array of property sets
)
{
IRowsetIndex *pIRowsetIndex = NULL;
DBORDINAL cColumns=0;
ULONG cIndexPropSets=0, nPropSet, nProp;
DBINDEXCOLUMNDESC *rgOutIndexColumnDesc = NULL;
DBPROPSET *rgIndexPropSets = NULL;
BOOL fResult = FALSE, fProp=TRUE;
DBPROP *pProp=NULL;
DBPROPSTATUS dwStatus;
VARIANT *pvValue;
DBPROPID dwPropID;
// Use IRowsetIndex->GetIndexInfo to check how the index was set
TESTC_(m_hr = m_pIOpenRowset->OpenRowset(
NULL,
m_ulIRowsetIndex & OIS_INTEGRATED ? pTableID : NULL,
pIndexID,
IID_IRowsetIndex,
0,
NULL,
(IUnknown**)&pIRowsetIndex
), S_OK);
TESTC_(pIRowsetIndex->GetIndexInfo(&cColumns, &rgOutIndexColumnDesc, &cIndexPropSets, &rgIndexPropSets), S_OK);
if (!rgPropertySets)
{
fResult = TRUE;
goto CLEANUP;
}
for (nPropSet=0; nPropSet<cPropertySets; nPropSet++)
{
if (DBPROPSET_INDEX != rgPropertySets[nPropSet].guidPropertySet)
{
for (nProp=0; nProp<rgPropertySets[nPropSet].cProperties; nProp++)
{
if (!COMPARE(rgPropertySets[nPropSet].rgProperties[nProp].dwStatus, DBPROPSTATUS_NOTSUPPORTED))
fProp = FALSE;
}
continue;
}
if (!rgPropertySets[nPropSet].rgProperties)
continue;
for (nProp=0; nProp<rgPropertySets[nPropSet].cProperties; nProp++)
{
dwStatus = rgPropertySets[nPropSet].rgProperties[nProp].dwStatus;
dwPropID = rgPropertySets[nPropSet].rgProperties[nProp].dwPropertyID;
pvValue = &rgPropertySets[nPropSet].rgProperties[nProp].vValue;
// try to find coresponding property got from IRowsetIndex
if (!FindProperty( dwPropID,
rgPropertySets[nPropSet].guidPropertySet,
cIndexPropSets,
rgIndexPropSets,
&pProp))
{
fProp = fProp && COMPARE(dwStatus, DBPROPSTATUS_NOTSUPPORTED);
continue;
}
// prop status were check in CreateAndCheckIndex by calling CheckProperty
if (DBPROPSTATUS_OK == dwStatus)
fProp = fProp && COMPARE(CompareVariant(&pProp->vValue, pvValue), TRUE);
}
}
fResult = fProp;
CLEANUP:
SAFE_RELEASE(pIRowsetIndex);
FreeProperties(&cIndexPropSets, &rgIndexPropSets);
FreeIndexColumnDesc(&cColumns, &rgOutIndexColumnDesc, TRUE);
return fResult;
} //CheckIndex2
//--------------------------------------------------------------------------
// CAlterIndex::GetIndexValue
// Read the value of a column in the index schema rowset
// if *pfSet is TRUE then there is a coparison value for the value read,
// otherwise the new value will be used for further comparisons => save
// it in *pVariable and set *pfSet to TRUE
// RETURNS FALSE if the value was read and differ than the original one
//
BOOL CAlterIndex::GetIndexValue(
LPVOID pVariable, // [OUT] value read
BOOL *pfSet, // [OUT] if the value is set
DBBINDING *rgDBBINDING, // [IN] binding array
ULONG cColumn, // [IN] column to be read
ULONG ulDBTYPE, // [IN] type of property variant
BYTE *pData, // [IN] pointer to read DATA stru
WCHAR *lpwszMesaj // [IN] message text for error
)
{
BOOL fRes = FALSE;
BOOL fWStrComp = FALSE;
DATA *pColumn = NULL;
TESTC(NULL != pData);
TESTC(NULL != rgDBBINDING);
TESTC(NULL != pVariable);
TESTC(NULL != pfSet);
fRes = TRUE;
// get the status of the read property value
pColumn = (DATA*) (pData+rgDBBINDING[cColumn].obStatus);
if (DBSTATUS_S_OK == pColumn->sStatus)
{
// get the value in pVariable
switch (ulDBTYPE)
{
case DBTYPE_I4:
if (!*pfSet)
{
*(LONG*)pVariable = *(LONG*)(&(pColumn->bValue));
*pfSet = TRUE;
}
else
fRes = (*(LONG*)(&(pColumn->bValue)) == *(LONG*)pVariable);
break;
case DBTYPE_UI2:
if (!*pfSet)
{
*(unsigned short*)pVariable = *(unsigned short*)(&(pColumn->bValue));
*pfSet = TRUE;
}
else
fRes = (*(unsigned short*)(&(pColumn->bValue)) == *(unsigned short*)pVariable);
break;
case DBTYPE_I2:
if (!*pfSet)
{
*(SHORT*)pVariable = *(SHORT*)(&(pColumn->bValue));
*pfSet = TRUE;
}
else
fRes = (*(SHORT*)(&(pColumn->bValue)) == *(SHORT*)pVariable);
break;
case DBTYPE_BOOL:
if (!*pfSet)
{
*(VARIANT_BOOL*)pVariable = *(VARIANT_BOOL*)(&(pColumn->bValue));
*pfSet = TRUE;
}
else
fRes = (*(VARIANT_BOOL*)(&(pColumn->bValue)) == *(VARIANT_BOOL*)pVariable);
break;
case DBTYPE_WSTR:
if (!*pfSet)
{
TESTC(NULL != *(WCHAR**)pVariable);
// release the memory is wrongfully passed
if (!*(WCHAR*)pVariable)
SAFE_FREE(*(WCHAR**)pVariable);
// set the variable
*(WCHAR**)pVariable = wcsDuplicate(*(WCHAR**)(&(pColumn->bValue)));
*pfSet = TRUE;
}
else
// compare
fRes = (NULL != *(WCHAR**)pVariable)
&& S_OK == CompareID(&fWStrComp, *(WCHAR**)pVariable, (WCHAR*)(&(pColumn->bValue)), m_pIDBInitialize)
&& fWStrComp;
break;
default:
ASSERT(FALSE);
break;
}
if (!fRes)
odtLog << lpwszMesaj;
}
CLEANUP:
return fRes;
} //GetIndexValue
//--------------------------------------------------------------------------
// CAlterIndex::GetIndexValueFromFirstRow
// Read the value of a column in the indexe schema rowset
// RETURNS FALSE if the value was read and differ than the original one
//
BOOL CAlterIndex::GetIndexValueFromFirstRow(
LPVOID pVariable, // [OUT] value read
BOOL *pfSet, // [OUT] if the value is set
DBBINDING *rgDBBINDING, // [IN] binding array
ULONG cColumn, // [IN] column to be read
ULONG ulDBTYPE, // [IN] type of property variant
BYTE *pData, // [IN] pointer to read DATA stru
DBPROPID PropID, // [IN] property that is being read
ULONG cPropSets, // [IN] number of property sets
DBPROPSET *rgPropSets, // [IN] array of property sets
WCHAR *lpwszMesaj // [IN] message text for error
)
{
BOOL fRes = TRUE;
DBPROP *pProp = NULL;
TESTC(NULL != pfSet);
*pfSet = FALSE;
FindProperty(PropID, DBPROPSET_INDEX, cPropSets, rgPropSets, &pProp);
if (!pProp)
goto CLEANUP;
// get the variable value
switch (ulDBTYPE)
{
case DBTYPE_BOOL:
*(VARIANT_BOOL*)pVariable = V_BOOL(&pProp->vValue);
break;
case DBTYPE_I4:
*(LONG*)pVariable = V_I4(&pProp->vValue);
break;
case DBTYPE_UI2:
*(unsigned short*)pVariable = V_UI2(&pProp->vValue);
break;
case DBTYPE_I2:
*(SHORT*)pVariable = V_I2(&pProp->vValue);
break;
default:
TESTC(FALSE);
}
*pfSet = (DBPROPSTATUS_OK == pProp->dwStatus);
CLEANUP:
fRes = GetIndexValue(pVariable, pfSet, rgDBBINDING, cColumn, ulDBTYPE, pData, lpwszMesaj);
return fRes;
} //GetIndexValueFromFirstRow
//---------------------------------------------------------------------------
// CAlterIndex::DoesIndexExistInIndexSchemaRowset
//
// DoesIndexExist |
// If this index is on this table return true. If function runs correctly
// but doesn't find the table name, function will return S_OK, but fExists
// will be FALSE. If strIndexName is empty, returns E_FAIL. The index is sought in
// index schema rowset.
//
// @mfunc DoesIndexExist
// @rdesc HRESULT indicating success or failure
// @flag S_OK | Function ran without problem
// @flag E_FAIL | Function ran with problems
//
//---------------------------------------------------------------------------
HRESULT CAlterIndex::DoesIndexExistInIndexSchemaRowset(
DBID *pTableID, // @parm [IN] Table ID
DBID *pIndexID, // @parm [IN] Index ID
BOOL *pfExists // @parm [OUT] TRUE if index exists
)
{
HRESULT hr = E_FAIL;
DBCOUNTITEM cRowsObtained = 0; // number of rows returned, should be 1
HROW *rghRows = NULL; // array of handles of rows
IRowset *pIRowset = NULL; // returned rowset
const int cRest = 5; // restrictions on INDEXES Schema Rowset
VARIANT rgRestrictIndexes[cRest];
ULONG index;
// Initialize out param
*pfExists = FALSE;
// Set restrictions
for(index=0;index<cRest;index++)
VariantInit(&rgRestrictIndexes[index]);
TESTC(NULL != m_pIDBSchemaRowset);
TESTC(NULL != pTableID);
// At this time we don't have any way to determine if an index exists if
// we don't have the index name and table name, so we'll return S_OK and
// set *pfExists to false
// TODO: Track indexes so we can make sure a bogus index didn't get created
// either on success or error cases.
if (!pIndexID || !DBIDHasName(*pIndexID) || !DBIDHasName(*pTableID))
return S_OK;
// Note that the format for restrictions is not specified by OLEDB spec so provider
// is free to do whatever they want here.
// The restrictions passed to GetRowset must be unquoted for every provider I've tried.
// TODO: Remove any quotes.
if (DBIDHasName(*pIndexID))
{
rgRestrictIndexes[2].vt = VT_BSTR;
rgRestrictIndexes[2].bstrVal = SysAllocString(pIndexID->uName.pwszName);
}
if (DBIDHasName(*pTableID))
{
rgRestrictIndexes[4].vt = VT_BSTR;
rgRestrictIndexes[4].bstrVal = SysAllocString(pTableID->uName.pwszName);
}
if (!CHECK(hr = m_pIDBSchemaRowset->GetRowset(
NULL, // aggregation
DBSCHEMA_INDEXES, // REFGUID
cRest, // count of restrictions (1:types)
rgRestrictIndexes, // list of restrictions
IID_IRowset, // REFFID
0, // count of properties
NULL, // range of properties
(IUnknown**)&pIRowset // returned result set
),S_OK))
goto CLEANUP;
// Only do this once, if there is a rowset then
// there is an index on this table in the data source
hr=pIRowset->GetNextRows(0, 0, 1, &cRowsObtained, &rghRows);
if (pfExists)
*pfExists = (1 == cRowsObtained);
CHECK(hr=pIRowset->ReleaseRows(cRowsObtained,rghRows,NULL,NULL,NULL),S_OK);
if(FAILED(hr))
goto CLEANUP;
CLEANUP:
SAFE_RELEASE(pIRowset);
SAFE_FREE(rghRows);
for(index=0;index<cRest;index++)
GCHECK(VariantClear(&(rgRestrictIndexes[index])),S_OK);
return hr;
} //DoesIndexExistInIndexSchemaRowset
//---------------------------------------------------------------------------
// CAlterIndex::DoesIndexExistRowsetIndex
//
// DoesIndexExist |
// If this index is on this table return true. If function runs correctly
// but doesn't find the table name, function will return S_OK, but fExists
// will be FALSE. If strIndexName is empty, returns E_FAIL. The index is sought in
// index schema rowset.
//
// @mfunc DoesIndexExist
// @rdesc HRESULT indicating success or failure
// @flag S_OK | Function ran without problem
// @flag E_FAIL | Function ran with problems
//
//---------------------------------------------------------------------------
HRESULT CAlterIndex::DoesIndexExistRowsetIndex(
DBID *pTableID, // @parm [IN] Table ID
DBID *pIndexID, // @parm [IN] Index ID
BOOL *pfExist // @parm [OUT] TRUE if index exists
)
{
HRESULT hr;
IRowsetIndex *pRowsetIndex=NULL;
hr = m_pIOpenRowset->OpenRowset(NULL, pTableID, pIndexID, IID_IRowsetIndex, 0, NULL,
(IUnknown**)&pRowsetIndex);
if (pfExist)
*pfExist = (S_OK == hr)? TRUE: FALSE;
SAFE_RELEASE(pRowsetIndex);
return S_OK;
} //DoesIndexExistRowsetIndex
//---------------------------------------------------------------------------
// CAlterIndex::DoesIndexExist
//
// DoesIndexExist |
// If this index is on this table return true If function runs correctly
// but doesn't find the table name, function will return S_OK, but fExists
// will be FALSE. If strIndexName is empty, returns E_FAIL.
//
// @mfunc DoesIndexExist
// @rdesc HRESULT indicating success or failure
// @flag S_OK | Function ran without problem
// @flag E_FAIL | Function ran with problems
//
//---------------------------------------------------------------------------
HRESULT CAlterIndex::DoesIndexExist(
DBID *pTableID, // @parm [IN] Table ID
DBID *pIndexID, // @parm [IN] Index ID
BOOL *pfExists // @parm [OUT] TRUE if index exists
)
{
BOOL fIRowsetIndex = FALSE;
HRESULT hr = E_FAIL;
if (!pfExists)
return E_INVALIDARG;
//Cannot do any verification if none of the two exist.
if(!m_ulIRowsetIndex && !m_pIDBSchemaRowset)
return S_FALSE;
if (m_ulIRowsetIndex)
{
TESTC_(DoesIndexExistRowsetIndex(pTableID, pIndexID, pfExists), S_OK)
fIRowsetIndex = *pfExists;
}
if (m_pIDBSchemaRowset)
{
TESTC_(DoesIndexExistInIndexSchemaRowset(pTableID, pIndexID, pfExists), S_OK)
if(m_ulIRowsetIndex)
COMPARE(*pfExists, fIRowsetIndex);
}
hr = S_OK;
CLEANUP:
return hr;
} //DoesIndexExist
BOOL CAlterIndex::GetQualifierNames(
IUnknown * pSessionIUnknown,// [in] IUnknown off session object
LPWSTR pwszTableName, // [in] the name of the table
LPWSTR *ppwszCatalogName, // [out] catalog name
LPWSTR *ppwszSchemaName // [out] schema name
)
{
IRowset *pIRowset = NULL;
IDBSchemaRowset * pIDBSchmr = NULL;
ULONG cSchemas = 0;
GUID * pSchemas = NULL;
ULONG * pRestrictionSupport = NULL;
ULONG iSchema, iRestrict;
LONG_PTR rgColsToBind[TABLES_COLS] = {1, 2, 3};
BOOL fTablesRowset = FALSE;
BOOL fTableRestrict = FALSE;
VARIANT rgRestrictions[RESTRICTION_COUNT];
BYTE * pData = NULL;
HACCESSOR hAccessor;
DBBINDING * pBinding = NULL;
DBCOUNTITEM cBinding = 0;
DBLENGTH cbRowSize = 0;
DBCOUNTITEM cRows = 0;
HROW * pRow = NULL;
BOOL fTableFound = FALSE;
ULONG_PTR ulIdentCase = DBPROPVAL_IC_UPPER;
ULONG_PTR ulQuotedIdentCase = DBPROPVAL_IC_UPPER;
// Check args
TESTC(NULL != pwszTableName);
TESTC(NULL != ppwszCatalogName);
TESTC(NULL != ppwszSchemaName);
// See if we can get an IDBSchemaRowset interface
if (!VerifyInterface(pSessionIUnknown, IID_IDBSchemaRowset, SESSION_INTERFACE,
(IUnknown **)&pIDBSchmr))
{
// Then the best we can do is get the catalog name from DBPROP_CURRENTCATALOG
GetProperty(DBPROP_CURRENTCATALOG, DBPROPSET_DATASOURCE, pSessionIUnknown, ppwszCatalogName);
goto CLEANUP;
}
// we've got to either remove
// the quotes or convert to proper case if DBPROP_IDENTIFIERCASE happens to
// be different than DBPROP_QUOTEDIDENTIFIERCASE and the QUOTEDIDENTIFIERCASE
// is DBPROPVAL_IC_SENSITIVE.
GetProperty(DBPROP_IDENTIFIERCASE, DBPROPSET_DATASOURCEINFO,
m_pThisTestModule->m_pIUnknown,&ulIdentCase);
GetProperty(DBPROP_QUOTEDIDENTIFIERCASE, DBPROPSET_DATASOURCEINFO,
m_pThisTestModule->m_pIUnknown,&ulQuotedIdentCase);
// Need to convert identifier to upper case or lower case
if (ulIdentCase == DBPROPVAL_IC_UPPER)
_wcsupr(pwszTableName);
else if (ulIdentCase == DBPROPVAL_IC_LOWER)
_wcslwr(pwszTableName);
// Find out of the TABLES rowset is supported
TESTC_(pIDBSchmr->GetSchemas(&cSchemas, &pSchemas, &pRestrictionSupport), S_OK);
for (iSchema = 0; iSchema < cSchemas; iSchema++)
{
if (pSchemas[iSchema] == DBSCHEMA_TABLES)
{
fTablesRowset = TRUE;
// See if the tablename restriction is supported
if (pRestrictionSupport[iSchema] & TABLE_RESTRICT)
fTableRestrict = TRUE;
break;
}
}
if (!fTablesRowset)
{
// Then the best we can do is get the catalog name from DBPROP_CURRENTCATALOG
GetProperty(DBPROP_CURRENTCATALOG, DBPROPSET_DATASOURCE, pSessionIUnknown, ppwszCatalogName);
goto CLEANUP;
}
// Initialize restrictions
for (iRestrict = 0; iRestrict < RESTRICTION_COUNT; iRestrict++)
VariantInit(&rgRestrictions[iRestrict]);
// Set the table restriction, if supported
if (fTableRestrict)
{
V_VT(&rgRestrictions[TABLE_RESTRICT-1]) = VT_BSTR;
V_BSTR(&rgRestrictions[TABLE_RESTRICT-1]) = SysAllocString(pwszTableName);
}
//Obtain Schema TABLES Rowset
TESTC_(pIDBSchmr->GetRowset(NULL, DBSCHEMA_TABLES, RESTRICTION_COUNT, rgRestrictions,
IID_IRowset, 0, NULL, (IUnknown **)&pIRowset), S_OK);
TESTC_(GetAccessorAndBindings(
pIRowset, // @parm [IN] Rowset or command to create Accessor for
DBACCESSOR_ROWDATA, // @parm [IN] Properties of the Accessor
&hAccessor, // @parm [OUT] Accessor created
&pBinding, // @parm [OUT] Array of DBBINDINGS
&cBinding, // @parm [OUT] Count of bindings
&cbRowSize, // @parm [OUT] length of a row
DBPART_VALUE|DBPART_LENGTH|DBPART_STATUS, // @parm [IN] Types of binding to do (Value, Status, and/or Length)
USE_COLS_TO_BIND_ARRAY, // @parm [IN] Which columns will be used in the bindings
FORWARD, // @parm [IN] Order to bind columns in accessor
NO_COLS_BY_REF, // @parm [IN] Which columns to bind by reference (fixed, variable, all or none)
NULL, // @parm [OUT] Array of DBCOLUMNINFO
NULL, // @parm [OUT] Count of Columns, also count of ColInfo elements
NULL, // @parm [OUT] ppStringsBuffer
DBTYPE_EMPTY, // @parm [IN] Modifier to be OR'd with each binding type.
TABLES_COLS, // @parm [IN] Used only if eColsToBind = USE_COLS_TO_BIND_ARRAY
rgColsToBind // @parm [IN] Used only if eColsToBind = USE_COLS_TO_BIND_ARRAY
), S_OK);
// Allocate a buffer to hold the results
SAFE_ALLOC(pData, BYTE, cbRowSize);
//Try to find the specified row with this table name
while(S_OK == pIRowset->GetNextRows(NULL, 0, 1, &cRows, &pRow))
{
DATA * pCol = (DATA *)(pData + pBinding[2].obStatus);
TESTC(cRows == 1);
//GetData for this row
TESTC_(pIRowset->GetData(*pRow, hAccessor, pData),S_OK);
// If the table name isn't NULL or an error
if(pCol->sStatus ==DBSTATUS_S_OK)
{
// See if it matches
if(!wcscmp(pwszTableName, (LPWSTR)pCol->bValue))
{
DATA * pCatalogName = (DATA *)(pData + pBinding[0].obStatus);
DATA * pSchemaName = (DATA *)(pData + pBinding[1].obStatus);
fTableFound = TRUE;
//Catalog Name
if(pCatalogName->sStatus ==DBSTATUS_S_OK)
*ppwszCatalogName = wcsDuplicate((LPWSTR)pCatalogName->bValue);
//Schema Name
if(pSchemaName->sStatus ==DBSTATUS_S_OK)
*ppwszSchemaName = wcsDuplicate((LPWSTR)pSchemaName->bValue);
break;
}
}
TESTC_(pIRowset->ReleaseRows(cRows, pRow, NULL, NULL, NULL), S_OK);
}
COMPARE(fTableFound, TRUE);
CLEANUP:
CHECK(pIRowset->ReleaseRows(cRows, pRow, NULL, NULL, NULL), S_OK);
if (fTableRestrict)
VariantClear(&rgRestrictions[TABLE_RESTRICT-1]);
PROVIDER_FREE(pSchemas);
PROVIDER_FREE(pRestrictionSupport);
PROVIDER_FREE(pRow);
PROVIDER_FREE(pData);
PROVIDER_FREE(pBinding);
SAFE_RELEASE(pIRowset);
SAFE_RELEASE(pIDBSchmr);
return fTableFound;
}
HRESULT CAlterIndex::CleanUpIndex(
DBID *pTableID,
DBID **ppIndexID,
DBINDEXCOLUMNDESC * pIndexColumnDescs,
ULONG * pcPropertySets,
DBPROPSET ** ppPropertySets
)
{
HRESULT hr = S_OK;
// Drop the index we created
if (pTableID && ppIndexID && *ppIndexID)
CHECK(hr = m_pIIndexDef->DropIndex(pTableID, *ppIndexID), S_OK);
if (ppIndexID)
{
ReleaseDBID(*ppIndexID);
*ppIndexID= NULL;
}
// Free props
if (pcPropertySets && ppPropertySets)
FreeProperties(pcPropertySets, ppPropertySets);
// Note the DBIDs in this array just point to the appropriate column
// in CCol and so we shouldn't free the DBIDs.
SAFE_FREE(pIndexColumnDescs);
return hr;
}
void CAlterIndex::FreeIndexColumnDesc(DBORDINAL * pcColDesc, DBINDEXCOLUMNDESC ** ppIndexColumnDesc, BOOL fFreeBuf)
{
ULONG iColDesc;
ASSERT(pcColDesc && ppIndexColumnDesc);
if (*ppIndexColumnDesc)
{
for (iColDesc = 0; iColDesc < *pcColDesc; iColDesc++)
{
ReleaseDBID((*ppIndexColumnDesc)[iColDesc].pColumnID);
}
if (fFreeBuf)
SAFE_FREE(*ppIndexColumnDesc);
}
*pcColDesc = 0;
}
//*-----------------------------------------------------------------------
// Test Case Section
//*-----------------------------------------------------------------------
// {{ TCW_TEST_CASE_MAP(TCAI_SingCol)
//*-----------------------------------------------------------------------
// @class Test case for AlterIndex.
//
class TCAI_SingCol : public CAlterIndex {
public:
// @cmember Static array of variations
DECLARE_TEST_CASE_DATA();
public:
// {{ TCW_DECLARE_FUNCS
// @cmember Execution Routine
DECLARE_TEST_CASE_FUNCS(TCAI_SingCol,CAlterIndex);
// }} TCW_DECLARE_FUNCS_END
// @cmember Initialization Routine
virtual BOOL Init();
// @cmember Termination Routine
virtual BOOL Terminate();
// {{ TCW_TESTVARS()
// @cmember General - Verify Session object
int Variation_1();
// @cmember General - Change index name to names of various lengths.
int Variation_2();
// @cmember General - Change index name to a name of maximum length.
int Variation_3();
// @cmember General - Make names from wierd (valid) chars
int Variation_4();
// @cmember General - Change index name to DBKIND_GUID_NAME
int Variation_5();
// @cmember General - Change index name to DBKIND_GUID_PROPID
int Variation_6();
// @cmember General - Change index name to DBKIND_PGUID_NAME
int Variation_7();
// @cmember General - Change index name to DBKIND_PGUID_PROPID
int Variation_8();
// @cmember General - Change index name to DBKIND_PROPID
int Variation_9();
// @cmember General - Change index name to DBKIND_GUID
int Variation_10();
// @cmember General - pNewIndexID same as pIndexID (and no props)
int Variation_11();
// @cmember General - Change index name and one prop
int Variation_12();
// @cmember General - Change index name and several props
int Variation_13();
// @cmember General - Change index name and props (OPTIONAL)
int Variation_14();
// @cmember General - Change index name and props (SETIFCHEAP)
int Variation_15();
// @cmember General - try to set some index and some non-index props.
int Variation_16();
// @cmember General - pNewIndexID is NULL, set some props
int Variation_17();
// @cmember General - pNewIndexID is same as pIndexID, set some props
int Variation_18();
// @cmember General - pNewIndexID is NULL, no props
int Variation_19();
// @cmember General - AlterIndex for all data types that can have indexes
int Variation_20();
// @cmember General - Create several indexes and alter each
int Variation_21();
// @cmember General - AlterIndex on multiple threads, same index
int Variation_22();
// @cmember General - AlterIndex on multiple threads, different indexes
int Variation_23();
// @cmember General - AlterIndex on multiple threads, two tables to same index name
int Variation_24();
// @cmember General - AlterIndex on multiple threads, name on one, props on another
int Variation_25();
// @cmember General - AlterIndex on index created by command
int Variation_26();
// @cmember General - AlterIndex with quoted name
int Variation_27();
// @cmember General - AlterIndex with qualified and quoted name
int Variation_28();
// @cmember General - AlterIndex to same name as PrimaryKey constraint
int Variation_29();
// @cmember General - AlterIndex on temp table
int Variation_30();
// @cmember General - pIndexID is DBKIND_GUID_NAME
int Variation_31();
// @cmember General - pIndexID is DBKIND_GUID_PROPID
int Variation_32();
// @cmember General - pIndexID is DBKIND_PGUID_NAME
int Variation_33();
// @cmember General - pIndexID is DBKIND_PGUID_PROPID
int Variation_34();
// @cmember General - pIndexID is DBKIND_PROPID
int Variation_35();
// @cmember General - pIndexID is DBKIND_GUID
int Variation_36();
// @cmember General - AlterIndex with rowset open on different table
int Variation_37();
// }} TCW_TESTVARS_END
} ;
// {{ TCW_TESTCASE(TCAI_SingCol)
#define THE_CLASS TCAI_SingCol
BEG_TEST_CASE(TCAI_SingCol, CAlterIndex, L"Test case for AlterIndex.")
TEST_VARIATION(1, L"General - Verify Session object")
TEST_VARIATION(2, L"General - Change index name to names of various lengths.")
TEST_VARIATION(3, L"General - Change index name to a name of maximum length.")
TEST_VARIATION(4, L"General - Make names from wierd (valid) chars")
TEST_VARIATION(5, L"General - Change index name to DBKIND_GUID_NAME")
TEST_VARIATION(6, L"General - Change index name to DBKIND_GUID_PROPID")
TEST_VARIATION(7, L"General - Change index name to DBKIND_PGUID_NAME")
TEST_VARIATION(8, L"General - Change index name to DBKIND_PGUID_PROPID")
TEST_VARIATION(9, L"General - Change index name to DBKIND_PROPID")
TEST_VARIATION(10, L"General - Change index name to DBKIND_GUID")
TEST_VARIATION(11, L"General - pNewIndexID same as pIndexID (and no props)")
TEST_VARIATION(12, L"General - Change index name and one prop")
TEST_VARIATION(13, L"General - Change index name and several props")
TEST_VARIATION(14, L"General - Change index name and props (OPTIONAL)")
TEST_VARIATION(15, L"General - Change index name and props (SETIFCHEAP)")
TEST_VARIATION(16, L"General - try to set some index and some non-index props.")
TEST_VARIATION(17, L"General - pNewIndexID is NULL, set some props")
TEST_VARIATION(18, L"General - pNewIndexID is same as pIndexID, set some props")
TEST_VARIATION(19, L"General - pNewIndexID is NULL, no props")
TEST_VARIATION(20, L"General - AlterIndex for all data types that can have indexes")
TEST_VARIATION(21, L"General - Create several indexes and alter each")
TEST_VARIATION(22, L"General - AlterIndex on multiple threads, same index")
TEST_VARIATION(23, L"General - AlterIndex on multiple threads, different indexes")
TEST_VARIATION(24, L"General - AlterIndex on multiple threads, two tables to same index name")
TEST_VARIATION(25, L"General - AlterIndex on multiple threads, name on one, props on another")
TEST_VARIATION(26, L"General - AlterIndex on index created by command")
TEST_VARIATION(27, L"General - AlterIndex with quoted name")
TEST_VARIATION(28, L"General - AlterIndex with qualified and quoted name")
TEST_VARIATION(29, L"General - AlterIndex to same name as PrimaryKey constraint")
TEST_VARIATION(30, L"General - AlterIndex on temp table")
TEST_VARIATION(31, L"General - pIndexID is DBKIND_GUID_NAME")
TEST_VARIATION(32, L"General - pIndexID is DBKIND_GUID_PROPID")
TEST_VARIATION(33, L"General - pIndexID is DBKIND_PGUID_NAME")
TEST_VARIATION(34, L"General - pIndexID is DBKIND_PGUID_PROPID")
TEST_VARIATION(35, L"General - pIndexID is DBKIND_PROPID")
TEST_VARIATION(36, L"General - pIndexID is DBKIND_GUID")
TEST_VARIATION(37, L"General - AlterIndex with rowset open on different table")
END_TEST_CASE()
#undef THE_CLASS
// }} TCW_TESTCASE_END
// }} TCW_TEST_CASE_MAP_END
// {{ TCW_TEST_CASE_MAP(TCBoundary_SingCol)
//*-----------------------------------------------------------------------
// @class Boundary cases
//
class TCBoundary_SingCol : public CAlterIndex {
public:
// @cmember Static array of variations
DECLARE_TEST_CASE_DATA();
public:
// {{ TCW_DECLARE_FUNCS
// @cmember Execution Routine
DECLARE_TEST_CASE_FUNCS(TCBoundary_SingCol,CAlterIndex);
// }} TCW_DECLARE_FUNCS_END
// @cmember Initialization Routine
virtual BOOL Init();
// @cmember Termination Routine
virtual BOOL Terminate();
// {{ TCW_TESTVARS()
// @cmember E_INVALIDARG - pTableID = NULL
int Variation_1();
// @cmember E_INVALIDARG - pIndexID = NULL
int Variation_2();
// @cmember E_INVALIDARG - pTableID = NULL and pIndexID = NULL
int Variation_3();
// @cmember E_INVALIDARG - cPropSets > 0 and rgPropSets NULL
int Variation_4();
// @cmember E_INVALIDARG - cProperties != 0 and rgProperties NULL
int Variation_5();
// @cmember DB_E_NOTABLE - *pTableID == DB_NULLID
int Variation_6();
// @cmember DB_E_NOTABLE - pTableID->uName is NULL
int Variation_7();
// @cmember DB_E_NOTABLE - pTableID->uName is empty string
int Variation_8();
// @cmember DB_E_NOTABLE - Table name invalid
int Variation_9();
// @cmember DB_E_NOTABLE - Table name exceeds max length
int Variation_10();
// @cmember DB_E_NOTABLE - Table does not exist
int Variation_11();
// @cmember DB_E_NOINDEX - Index does not exist
int Variation_12();
// @cmember DB_E_NOINDEX - *pIndexID == DB_NULLID
int Variation_13();
// @cmember DB_E_NOINDEX - pIndexID->uName is NULL
int Variation_14();
// @cmember DB_E_NOINDEX - pIndexID->uName is empty string
int Variation_15();
// @cmember DB_E_NOINDEX - pIndexID name is invalid
int Variation_16();
// @cmember DB_E_NOINDEX - pIndexID name exceeds max name length
int Variation_17();
// @cmember DB_E_DUPLICATEINDEXID - The new index already exists
int Variation_18();
// @cmember DBSEC_E_PERMISSIONDENIED - Insufficient permissions to alter index
int Variation_19();
// @cmember DB_E_BADINDEXID - pNewIndexID == DB_NULLID
int Variation_20();
// @cmember DB_E_BADINDEXID - pNewIndexID->uName is NULL
int Variation_21();
// @cmember DB_E_BADINDEXID - pNewIndexID->uName is empty string
int Variation_22();
// @cmember DB_E_BADINDEXID - Specify an invalid new index ID
int Variation_23();
// @cmember DB_E_BADINDEXID - pNewIndexID name exceeds max name length
int Variation_24();
// @cmember DB_E_INDEXINUSE - AlterIndex with index in use
int Variation_25();
// @cmember DB_E_TABLEINUSE - AlterIndex with table in use
int Variation_26();
// @cmember S_OK - cPropSets == 0, rgPropSets is ignored
int Variation_27();
// @cmember DB_E_NOINDEX - AlterIndex on a dropped index
int Variation_28();
// @cmember DB_E_NOTABLE - Pass procedure name as existing table name
int Variation_29();
// @cmember DB_E_NOINDEX - Pass procedure name as existing index name
int Variation_30();
// @cmember DB_E_NOINDEX - Pass valid index from different table as existing index name
int Variation_31();
// @cmember DB_E_ERRORSOCCURRED - Alter second index on table to be duplicate primary key
int Variation_32();
// @cmember DB_S_ERRORSOCCURRED - Alter second index on table to be duplicate primary key
int Variation_33();
// }} TCW_TESTVARS_END
} ;
// {{ TCW_TESTCASE(TCBoundary_SingCol)
#define THE_CLASS TCBoundary_SingCol
BEG_TEST_CASE(TCBoundary_SingCol, CAlterIndex, L"Boundary cases")
TEST_VARIATION(1, L"E_INVALIDARG - pTableID = NULL")
TEST_VARIATION(2, L"E_INVALIDARG - pIndexID = NULL")
TEST_VARIATION(3, L"E_INVALIDARG - pTableID = NULL and pIndexID = NULL")
TEST_VARIATION(4, L"E_INVALIDARG - cPropSets > 0 and rgPropSets NULL")
TEST_VARIATION(5, L"E_INVALIDARG - cProperties != 0 and rgProperties NULL")
TEST_VARIATION(6, L"DB_E_NOTABLE - *pTableID == DB_NULLID")
TEST_VARIATION(7, L"DB_E_NOTABLE - pTableID->uName is NULL")
TEST_VARIATION(8, L"DB_E_NOTABLE - pTableID->uName is empty string")
TEST_VARIATION(9, L"DB_E_NOTABLE - Table name invalid")
TEST_VARIATION(10, L"DB_E_NOTABLE - Table name exceeds max length")
TEST_VARIATION(11, L"DB_E_NOTABLE - Table does not exist")
TEST_VARIATION(12, L"DB_E_NOINDEX - Index does not exist")
TEST_VARIATION(13, L"DB_E_NOINDEX - *pIndexID == DB_NULLID")
TEST_VARIATION(14, L"DB_E_NOINDEX - pIndexID->uName is NULL")
TEST_VARIATION(15, L"DB_E_NOINDEX - pIndexID->uName is empty string")
TEST_VARIATION(16, L"DB_E_NOINDEX - pIndexID name is invalid")
TEST_VARIATION(17, L"DB_E_NOINDEX - pIndexID name exceeds max name length")
TEST_VARIATION(18, L"DB_E_DUPLICATEINDEXID - The new index already exists")
TEST_VARIATION(19, L"DBSEC_E_PERMISSIONDENIED - Insufficient permissions to alter index")
TEST_VARIATION(20, L"DB_E_BADINDEXID - pNewIndexID == DB_NULLID")
TEST_VARIATION(21, L"DB_E_BADINDEXID - pNewIndexID->uName is NULL")
TEST_VARIATION(22, L"DB_E_BADINDEXID - pNewIndexID->uName is empty string")
TEST_VARIATION(23, L"DB_E_BADINDEXID - Specify an invalid new index ID")
TEST_VARIATION(24, L"DB_E_BADINDEXID - pNewIndexID name exceeds max name length")
TEST_VARIATION(25, L"DB_E_INDEXINUSE - AlterIndex with index in use")
TEST_VARIATION(26, L"DB_E_TABLEINUSE - AlterIndex with table in use")
TEST_VARIATION(27, L"S_OK - cPropSets == 0, rgPropSets is ignored")
TEST_VARIATION(28, L"DB_E_NOINDEX - AlterIndex on a dropped index")
TEST_VARIATION(29, L"DB_E_NOTABLE - Pass procedure name as existing table name")
TEST_VARIATION(30, L"DB_E_NOINDEX - Pass procedure name as existing index name")
TEST_VARIATION(31, L"DB_E_NOINDEX - Pass valid index from different table as existing index name")
TEST_VARIATION(32, L"DB_E_ERRORSOCCURRED - Alter second index on table to be duplicate primary key")
TEST_VARIATION(33, L"DB_S_ERRORSOCCURRED - Alter second index on table to be duplicate primary key")
END_TEST_CASE()
#undef THE_CLASS
// }} TCW_TESTCASE_END
// }} TCW_TEST_CASE_MAP_END
// {{ TCW_TEST_CASE_MAP(TCProp_SingCol)
//*-----------------------------------------------------------------------
// @class Property related tests
//
class TCProp_SingCol : public CAlterIndex {
public:
// @cmember Static array of variations
DECLARE_TEST_CASE_DATA();
public:
// {{ TCW_DECLARE_FUNCS
// @cmember Execution Routine
DECLARE_TEST_CASE_FUNCS(TCProp_SingCol,CAlterIndex);
// }} TCW_DECLARE_FUNCS_END
// @cmember Initialization Routine
virtual BOOL Init();
// @cmember Termination Routine
virtual BOOL Terminate();
// {{ TCW_TESTVARS()
// @cmember DBPROP_INDEX_AUTOUPDATE
int Variation_1();
// @cmember DBPROP_INDEX_CLUSTERED
int Variation_2();
// @cmember DBPROP_INDEX_NULLS
int Variation_3();
// @cmember DBPROP_INDEX_PRIMARYKEY
int Variation_4();
// @cmember DBPROP_INDEX_SORTBOOKMARKS
int Variation_5();
// @cmember DBPROP_INDEX_TEMPINDEX
int Variation_6();
// @cmember DBPROP_INDEX_TYPE
int Variation_7();
// @cmember DBPROP_INDEX_UNIQUE
int Variation_8();
// @cmember DBPROP_INDEX_FILLFACTOR
int Variation_9();
// @cmember DBPROP_INDEX_INITIALSIZE
int Variation_10();
// @cmember DBPROP_INDEX_NULLCOLLATION
int Variation_11();
// @cmember DBPROP_INDEX_SORTBOOKMARKS and DBPROP_INDEX_UNIQUE
int Variation_12();
// @cmember DBPROP_INDEX_UNIQUE and DBPROP_INDEX_PRIMARYKEY
int Variation_13();
// @cmember DBPROP_INDEX_UNIQUE and DBPROP_INDEX_NULLS
int Variation_14();
// @cmember DBPROP_INDEX_NULLS and DBPROP_INDEX_PRIMARYKEY
int Variation_15();
// @cmember DB_E_ERRORSOCCURRED - Non index property with DBPROP_REQUIRED
int Variation_16();
// @cmember DB_S_ERRORSOCCURRED - Non index property with DBPROP_SETIFCHEAP
int Variation_17();
// @cmember Invalid values for properties (unexpected type)
int Variation_18();
// @cmember Specify a property twice
int Variation_19();
// @cmember Set invalid value for prop (unexpected value)
int Variation_20();
// @cmember Set colid for prop
int Variation_21();
// @cmember Set non-index prop in DBPROPSET_INDEX
int Variation_22();
// @cmember Set array of propsets, one with 0 properties
int Variation_23();
// @cmember Set props with static property sets and properties
int Variation_24();
// @cmember Set invalid properties REQUIRED and change name, verify new name doesn't exist
int Variation_25();
// @cmember Set invalid properties OPTIONAL and change name, verify new name does exist
int Variation_26();
// }} TCW_TESTVARS_END
} ;
// {{ TCW_TESTCASE(TCProp_SingCol)
#define THE_CLASS TCProp_SingCol
BEG_TEST_CASE(TCProp_SingCol, CAlterIndex, L"Property related tests")
TEST_VARIATION(1, L"DBPROP_INDEX_AUTOUPDATE")
TEST_VARIATION(2, L"DBPROP_INDEX_CLUSTERED")
TEST_VARIATION(3, L"DBPROP_INDEX_NULLS")
TEST_VARIATION(4, L"DBPROP_INDEX_PRIMARYKEY")
TEST_VARIATION(5, L"DBPROP_INDEX_SORTBOOKMARKS")
TEST_VARIATION(6, L"DBPROP_INDEX_TEMPINDEX")
TEST_VARIATION(7, L"DBPROP_INDEX_TYPE")
TEST_VARIATION(8, L"DBPROP_INDEX_UNIQUE")
TEST_VARIATION(9, L"DBPROP_INDEX_FILLFACTOR")
TEST_VARIATION(10, L"DBPROP_INDEX_INITIALSIZE")
TEST_VARIATION(11, L"DBPROP_INDEX_NULLCOLLATION")
TEST_VARIATION(12, L"DBPROP_INDEX_SORTBOOKMARKS and DBPROP_INDEX_UNIQUE")
TEST_VARIATION(13, L"DBPROP_INDEX_UNIQUE and DBPROP_INDEX_PRIMARYKEY")
TEST_VARIATION(14, L"DBPROP_INDEX_UNIQUE and DBPROP_INDEX_NULLS")
TEST_VARIATION(15, L"DBPROP_INDEX_NULLS and DBPROP_INDEX_PRIMARYKEY")
TEST_VARIATION(16, L"DB_E_ERRORSOCCURRED - Non index property with DBPROP_REQUIRED")
TEST_VARIATION(17, L"DB_S_ERRORSOCCURRED - Non index property with DBPROP_SETIFCHEAP")
TEST_VARIATION(18, L"Invalid values for properties (unexpected type)")
TEST_VARIATION(19, L"Specify a property twice")
TEST_VARIATION(20, L"Set invalid value for prop (unexpected value)")
TEST_VARIATION(21, L"Set colid for prop")
TEST_VARIATION(22, L"Set non-index prop in DBPROPSET_INDEX")
TEST_VARIATION(23, L"Set array of propsets, one with 0 properties")
TEST_VARIATION(24, L"Set props with static property sets and properties")
TEST_VARIATION(25, L"Set invalid properties REQUIRED and change name, verify new name doesn't exist")
TEST_VARIATION(26, L"Set invalid properties OPTIONAL and change name, verify new name does exist")
END_TEST_CASE()
#undef THE_CLASS
// }} TCW_TESTCASE_END
// }} TCW_TEST_CASE_MAP_END
// {{ TCW_TEST_CASE_MAP(TCTransact)
//*-----------------------------------------------------------------------
// @class Commit/abort behavior for AlterIndex
//
class TCTransact : public CAlterIndex {
private:
// @cmember Static array of variations
DECLARE_TEST_CASE_DATA();
CTransaction * m_pTransact;
ULONG_PTR m_ulSupportedTxnDDL;
HRESULT m_hrTxn;
public:
// {{ TCW_DECLARE_FUNCS
// @cmember Execution Routine
DECLARE_TEST_CASE_FUNCS(TCTransact,CAlterIndex);
// }} TCW_DECLARE_FUNCS_END
TCTransact(void);
// @cmember Initialization Routine
virtual BOOL Init();
// @cmember Termination Routine
virtual BOOL Terminate();
int TestTxn(ETXN eTxn,BOOL fRetaining, BOOL fCreateInTxn = FALSE);
// {{ TCW_TESTVARS()
// @cmember Commit Retaining
int Variation_1();
// @cmember Commit Non Retaining
int Variation_2();
// @cmember Abort Retaining
int Variation_3();
// @cmember Abort Non Retaining
int Variation_4();
// @cmember Commit Retaining, create index in txn
int Variation_5();
// @cmember Commit Non Retaining, create index in txn
int Variation_6();
// @cmember Abort Retaining, create index in txn
int Variation_7();
// @cmember Abort Non Retaining, create index in txn
int Variation_8();
// }} TCW_TESTVARS_END
} ;
// {{ TCW_TESTCASE(TCTransact)
#define THE_CLASS TCTransact
BEG_TEST_CASE(TCTransact, CAlterIndex, L"Commit/abort behavior for AlterIndex")
TEST_VARIATION(1, L"Commit Retaining")
TEST_VARIATION(2, L"Commit Non Retaining")
TEST_VARIATION(3, L"Abort Retaining")
TEST_VARIATION(4, L"Abort Non Retaining")
TEST_VARIATION(5, L"Commit Retaining, create index in txn")
TEST_VARIATION(6, L"Commit Non Retaining, create index in txn")
TEST_VARIATION(7, L"Abort Retaining, create index in txn")
TEST_VARIATION(8, L"Abort Non Retaining, create index in txn")
END_TEST_CASE()
#undef THE_CLASS
// }} TCW_TESTCASE_END
// }} TCW_TEST_CASE_MAP_END
// }} END_DECLARE_TEST_CASES()
////////////////////////////////////////////////////////////////////////
// Copying Test Cases to make duplicate ones.
//
////////////////////////////////////////////////////////////////////////
#define COPY_TEST_CASE(theClass, baseClass) \
class theClass : public baseClass \
{ \
public: \
static const WCHAR m_wszTestCaseName[]; \
DECLARE_TEST_CASE_FUNCS(theClass, baseClass); \
}; \
const WCHAR theClass::m_wszTestCaseName[] = { L#theClass }; \
#define TEST_CASE_WITH_PARAM(iCase, theClass, param) \
case iCase: \
pCTestCase = new theClass(NULL); \
((theClass*)pCTestCase)->SetTestCaseParam(param); \
pCTestCase->SetOwningMod(iCase-1, pCThisTestModule); \
return pCTestCase;
//Make a copy of the test cases.
COPY_TEST_CASE(TCAI_SingColWithProp, TCAI_SingCol)
COPY_TEST_CASE(TCAI_MultCol, TCAI_SingCol)
COPY_TEST_CASE(TCBoundary_MultCol, TCBoundary_SingCol)
COPY_TEST_CASE(TCAI_MultColWithProp, TCAI_SingCol)
COPY_TEST_CASE(TCBoundary_MultColWithProp, TCBoundary_SingCol)
COPY_TEST_CASE(TCProp_MultCol, TCProp_SingCol)
//NOTE: The #ifdef block below is only for test wizard. TestWizard has too many
//strict rules in the parsing code and requires a 1:1 correspondence between
//testcases and the map. What the #else section is doing is basically "reusing"
//existing testcases by just passing in a parameter which changes the behvior.
//So we make LTM think there are several cases in here with different names, but in
//reality we only have to maintain code for the unique cases.
#if 0
// {{ TCW_TESTMODULE(ThisModule)
TEST_MODULE(4, ThisModule, gwszModuleDescrip)
TEST_CASE(1, TCAI_SingCol)
TEST_CASE(2, TCBoundary_SingCol)
TEST_CASE(3, TCProp_SingCol)
TEST_CASE(4, TCTransact)
END_TEST_MODULE()
// }} TCW_TESTMODULE_END
#else
TEST_MODULE(10, ThisModule, gwszModuleDescrip)
//1
TEST_CASE(1, TCAI_SingCol)
TEST_CASE(2, TCBoundary_SingCol)
//2
TEST_CASE_WITH_PARAM(3, TCAI_SingColWithProp, TC_SingleColProps)
//3
TEST_CASE_WITH_PARAM(4, TCAI_MultCol, TC_MultipleColsNoProps)
TEST_CASE_WITH_PARAM(5, TCBoundary_MultCol, TC_MultipleColsNoProps)
//4
TEST_CASE_WITH_PARAM(6, TCAI_MultColWithProp, TC_MultipleColsProps)
TEST_CASE_WITH_PARAM(7, TCBoundary_MultColWithProp, TC_MultipleColsProps)
//5
TEST_CASE_WITH_PARAM(8, TCProp_SingCol, TC_PropSingCol)
TEST_CASE_WITH_PARAM(9, TCProp_MultCol, TC_PropMultCol)
TEST_CASE(10, TCTransact)
END_TEST_MODULE()
#endif
// {{ TCW_TC_PROTOTYPE(TCAI_SingCol)
//*-----------------------------------------------------------------------
//| Test Case: TCAI_SingCol - Test case for AlterIndex.
//| Created: 7/30/1999
//*-----------------------------------------------------------------------
//*-----------------------------------------------------------------------
// @mfunc TestCase Initialization Routine
//
// @rdesc TRUE or FALSE
//
BOOL TCAI_SingCol::Init()
{
// {{ TCW_INIT_BASECLASS_CHECK
return CAlterIndex::Init();
// }}
}
// {{ TCW_VAR_PROTOTYPE(1)
//*-----------------------------------------------------------------------
// @mfunc General - Verify Session object
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCAI_SingCol::Variation_1()
{
TBEGIN
TESTC(DefaultObjectTesting(m_pIAlterIndex, SESSION_INTERFACE))
CLEANUP:
TRETURN
}
// }} TCW_VAR_PROTOTYPE_END
// {{ TCW_VAR_PROTOTYPE(2)
//*-----------------------------------------------------------------------
// @mfunc General - Change index name to names of various lengths.
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCAI_SingCol::Variation_2()
{
TBEGIN
HRESULT hr;
CDBID dbidNew(DBKIND_NAME, L"X");
TESTC_(hr = AlterIndex(m_pIndexID, &dbidNew), S_OK)
Refresh_m_pIndexID(hr, dbidNew);
dbidNew.uName.pwszName = BuildValidName(2, L"xy");
TESTC_(hr = AlterIndex(m_pIndexID, &dbidNew), S_OK)
Refresh_m_pIndexID(hr, dbidNew);
SAFE_FREE(dbidNew.uName.pwszName);
dbidNew.uName.pwszName = BuildValidName(15, L"a1b2c3");
TESTC_(hr = AlterIndex(m_pIndexID, &dbidNew), S_OK)
Refresh_m_pIndexID(hr, dbidNew);
SAFE_FREE(dbidNew.uName.pwszName);
dbidNew.uName.pwszName = BuildValidName(16, L"IAlterIndex");
TESTC_(hr = AlterIndex(m_pIndexID, &dbidNew), S_OK)
if(m_cMaxIndexName<63)
goto CLEANUP;
Refresh_m_pIndexID(hr, dbidNew);
SAFE_FREE(dbidNew.uName.pwszName);
dbidNew.uName.pwszName = BuildValidName(63, L"TheQuickBrownFoxJumpedOverTheLazyDog");
TESTC_(hr = AlterIndex(m_pIndexID, &dbidNew), S_OK)
if(m_cMaxIndexName<64)
goto CLEANUP;
Refresh_m_pIndexID(hr, dbidNew);
SAFE_FREE(dbidNew.uName.pwszName);
dbidNew.uName.pwszName = BuildValidName(64, L"ThisIsATestStringXYZ");
TESTC_(hr = AlterIndex(m_pIndexID, &dbidNew), S_OK)
if(m_cMaxIndexName<65)
goto CLEANUP;
Refresh_m_pIndexID(hr, dbidNew);
SAFE_FREE(dbidNew.uName.pwszName);
dbidNew.uName.pwszName = BuildValidName(65, L"Howareyou1234567890");
TESTC_(hr = AlterIndex(m_pIndexID, &dbidNew), S_OK)
if(m_cMaxIndexName<127)
goto CLEANUP;
Refresh_m_pIndexID(hr, dbidNew);
SAFE_FREE(dbidNew.uName.pwszName);
dbidNew.uName.pwszName = BuildValidName(127, L"TheQuickBrownFoxJumpedOverTheLazyDog1234567890");
TESTC_(hr = AlterIndex(m_pIndexID, &dbidNew), S_OK)
if(m_cMaxIndexName<128)
goto CLEANUP;
Refresh_m_pIndexID(hr, dbidNew);
SAFE_FREE(dbidNew.uName.pwszName);
dbidNew.uName.pwszName = BuildValidName(128, L"TheQuickBrownFoxJumpedOverTheLazyDog1234567890");
TESTC_(hr = AlterIndex(m_pIndexID, &dbidNew), S_OK)
if(m_cMaxIndexName<129)
goto CLEANUP;
Refresh_m_pIndexID(hr, dbidNew);
SAFE_FREE(dbidNew.uName.pwszName);
dbidNew.uName.pwszName = BuildValidName(129, L"TheQuickBrownFox0123456789JumpedOverTheLazyDog");
TESTC_(hr = AlterIndex(m_pIndexID, &dbidNew), S_OK)
CLEANUP:
Refresh_m_pIndexID(hr, dbidNew);
SAFE_FREE(dbidNew.uName.pwszName);
TRETURN
}
// }} TCW_VAR_PROTOTYPE_END
// {{ TCW_VAR_PROTOTYPE(3)
//*-----------------------------------------------------------------------
// @mfunc General - Change index name to a name of maximum length.
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCAI_SingCol::Variation_3()
{
TBEGIN
HRESULT hr;
CDBID dbidNew(DBKIND_NAME, BuildValidName(m_cMaxIndexName, L"XYZ"));
TESTC_(hr = AlterIndex(m_pIndexID, &dbidNew), S_OK)
CLEANUP:
Refresh_m_pIndexID(hr, dbidNew);
SAFE_FREE(dbidNew.uName.pwszName);
TRETURN
}
// }} TCW_VAR_PROTOTYPE_END
// {{ TCW_VAR_PROTOTYPE(4)
//*-----------------------------------------------------------------------
// @mfunc General - Make names from wierd (valid) chars
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCAI_SingCol::Variation_4()
{
TBEGIN
CDBID dbidNew(DBKIND_NAME, wcsDuplicate(m_pIndexID->uName.pwszName));
size_t iChar;
HRESULT hr = E_FAIL;
size_t cchName = wcslen(m_pIndexID->uName.pwszName);
WCHAR wszValidChar[2] = L"A";
WCHAR *pwszValidChars = L"`1234567890-=~!@#$%^&*()_+[]\\;',./{}|:\"<>?";
size_t cchValid = wcslen(pwszValidChars);
// There must be at least one character in the existing index
TESTC(cchName > 0);
// Replace the last character in the valid name with wierd valid ones
for (iChar = 0; iChar < cchValid; iChar++)
{
// Make sure this character doesn't appear in the invalid list
if (wcschr(m_pwszInvalidIndexChars, pwszValidChars[iChar]))
continue;
dbidNew.uName.pwszName[cchName-1] = pwszValidChars[iChar];
if (!CHECK(hr = AlterIndex(m_pIndexID, &dbidNew), S_OK))
{
wszValidChar[0] = pwszValidChars[iChar];
odtLog << L"Valid character # " << iChar << " '" << wszValidChar << L"' was invalid.\n\n";
}
Refresh_m_pIndexID(hr, dbidNew);
}
// Reset back to the valid name
wcscpy(dbidNew.uName.pwszName, m_pIndexID->uName.pwszName);
// Now try as starting characters
// Replace the first character in the valid name with invalid ones
for (iChar = 0; iChar < cchValid; iChar++)
{
// Make sure this character doesn't appear in the invalid list
if (wcschr(m_pwszInvalidIndexStartingChars, pwszValidChars[iChar]))
continue;
dbidNew.uName.pwszName[0] = pwszValidChars[iChar];
if (!CHECK(hr = AlterIndex(m_pIndexID, &dbidNew), S_OK))
{
wszValidChar[0] = pwszValidChars[iChar];
odtLog << L"Valid starting character # " << iChar << " '" << wszValidChar << L"' was invalid.\n\n";
}
Refresh_m_pIndexID(hr, dbidNew);
}
CLEANUP:
SAFE_FREE(dbidNew.uName.pwszName);
TRETURN
}
// }} TCW_VAR_PROTOTYPE_END
// {{ TCW_VAR_PROTOTYPE(5)
//*-----------------------------------------------------------------------
// @mfunc General - Change index name to DBKIND_GUID_NAME
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCAI_SingCol::Variation_5()
{
TBEGIN
HRESULT hr;
CDBID dbidNew(DBKIND_GUID_NAME, L"abc123");
dbidNew.uGuid.guid = DBGUID_DSO;
TEST2C_(hr = AlterIndex(m_pIndexID, &dbidNew), S_OK, DB_E_BADINDEXID)
if(DB_E_BADINDEXID == hr)
odtLog<<L"INFO: Index IDs of DBKIND_GUID_NAME are considered invalid.\n";
CLEANUP:
Refresh_m_pIndexID(hr, dbidNew);
TRETURN
}
// }} TCW_VAR_PROTOTYPE_END
// {{ TCW_VAR_PROTOTYPE(6)
//*-----------------------------------------------------------------------
// @mfunc General - Change index name to DBKIND_GUID_PROPID
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCAI_SingCol::Variation_6()
{
TBEGIN
HRESULT hr;
CDBID dbidNew(DBKIND_GUID_PROPID, NULL);
dbidNew.uName.ulPropid = 666;
dbidNew.uGuid.guid = DBGUID_DSO;
TEST2C_(hr = AlterIndex(m_pIndexID, &dbidNew), S_OK, DB_E_BADINDEXID)
if(DB_E_BADINDEXID == hr)
odtLog<<L"INFO: Index IDs of DBKIND_GUID_PROPID are considered invalid.\n";
CLEANUP:
Refresh_m_pIndexID(hr, dbidNew);
TRETURN
}
// }} TCW_VAR_PROTOTYPE_END
// {{ TCW_VAR_PROTOTYPE(7)
//*-----------------------------------------------------------------------
// @mfunc General - Change index name to DBKIND_PGUID_NAME
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCAI_SingCol::Variation_7()
{
TBEGIN
HRESULT hr;
CDBID dbidNew(DBKIND_PGUID_NAME, L"abc123");
GUID guid = DBGUID_ROW;
dbidNew.uGuid.pguid = &guid;
TEST2C_(hr = AlterIndex(m_pIndexID, &dbidNew), S_OK, DB_E_BADINDEXID)
if(DB_E_BADINDEXID == hr)
odtLog<<L"INFO: Index IDs of DBKIND_PGUID_NAME are considered invalid.\n";
CLEANUP:
Refresh_m_pIndexID(hr, dbidNew);
TRETURN
}
// }} TCW_VAR_PROTOTYPE_END
// {{ TCW_VAR_PROTOTYPE(8)
//*-----------------------------------------------------------------------
// @mfunc General - Change index name to DBKIND_PGUID_PROPID
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCAI_SingCol::Variation_8()
{
TBEGIN
HRESULT hr;
CDBID dbidNew(DBKIND_PGUID_PROPID, NULL);
GUID guid = DBGUID_ROW;
dbidNew.uName.ulPropid = 666;
dbidNew.uGuid.pguid = &guid;
TEST2C_(hr = AlterIndex(m_pIndexID, &dbidNew), S_OK, DB_E_BADINDEXID)
if(DB_E_BADINDEXID == hr)
odtLog<<L"INFO: Index IDs of DBKIND_PGUID_PROPID are considered invalid.\n";
CLEANUP:
Refresh_m_pIndexID(hr, dbidNew);
TRETURN
}
// }} TCW_VAR_PROTOTYPE_END
// {{ TCW_VAR_PROTOTYPE(9)
//*-----------------------------------------------------------------------
// @mfunc General - Change index name to DBKIND_PROPID
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCAI_SingCol::Variation_9()
{
TBEGIN
HRESULT hr;
CDBID dbidNew(DBKIND_PROPID, NULL);
dbidNew.uName.ulPropid = 666;
TEST2C_(hr = AlterIndex(m_pIndexID, &dbidNew), S_OK, DB_E_BADINDEXID)
if(DB_E_BADINDEXID == hr)
odtLog<<L"INFO: Index IDs of DBKIND_PROPID are considered invalid.\n";
CLEANUP:
Refresh_m_pIndexID(hr, dbidNew);
TRETURN
}
// }} TCW_VAR_PROTOTYPE_END
// {{ TCW_VAR_PROTOTYPE(10)
//*-----------------------------------------------------------------------
// @mfunc General - Change index name to DBKIND_GUID
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCAI_SingCol::Variation_10()
{
TBEGIN
HRESULT hr;
CDBID dbidNew(DBKIND_GUID, NULL);
dbidNew.uGuid.guid = DBGUID_DSO;
TEST2C_(hr = AlterIndex(m_pIndexID, &dbidNew), S_OK, DB_E_BADINDEXID)
if(DB_E_BADINDEXID == hr)
odtLog<<L"INFO: Index IDs of DBKIND_GUID are considered invalid.\n";
CLEANUP:
Refresh_m_pIndexID(hr, dbidNew);
TRETURN
}
// }} TCW_VAR_PROTOTYPE_END
// {{ TCW_VAR_PROTOTYPE(11)
//*-----------------------------------------------------------------------
// @mfunc General - pNewIndexID same as pIndexID (and no props)
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCAI_SingCol::Variation_11()
{
TBEGIN
HRESULT hr;
DBID dbidNew = DB_NULLID;
DuplicateDBID(*m_pIndexID, &dbidNew);
TESTC_(hr = AlterIndex(m_pIndexID, &dbidNew), S_OK)
CLEANUP:
Refresh_m_pIndexID(hr, dbidNew);
ReleaseDBID(&dbidNew, FALSE);
TRETURN
}
// }} TCW_VAR_PROTOTYPE_END
// {{ TCW_VAR_PROTOTYPE(12)
//*-----------------------------------------------------------------------
// @mfunc General - Change index name and one prop
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCAI_SingCol::Variation_12()
{
TBEGIN
HRESULT hr;
CDBID dbidNew(DBKIND_NAME, L"JamesBond007");
//Set one Index prop (optional)
SetProperty(DBPROP_INDEX_UNIQUE, DBPROPSET_INDEX, &m_cPropSets, &m_rgPropSets, (void*)VARIANT_TRUE, DBTYPE_BOOL, DBPROPOPTIONS_OPTIONAL);
TEST2C_(hr = AlterIndex(m_pIndexID, &dbidNew), S_OK, DB_S_ERRORSOCCURRED)
CLEANUP:
Refresh_m_pIndexID(hr, dbidNew);
FreeProperties(&m_cPropSets, &m_rgPropSets);
TRETURN
}
// }} TCW_VAR_PROTOTYPE_END
// {{ TCW_VAR_PROTOTYPE(13)
//*-----------------------------------------------------------------------
// @mfunc General - Change index name and several props
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCAI_SingCol::Variation_13()
{
TBEGIN
HRESULT hr;
CDBID dbidNew(DBKIND_NAME, L"SupermanSSS");
//Set 2 props as optional. Also set a 3rd prop if it is
//settable.
SetProperty(DBPROP_INDEX_UNIQUE, DBPROPSET_INDEX, &m_cPropSets, &m_rgPropSets, (void*)VARIANT_TRUE, DBTYPE_BOOL, DBPROPOPTIONS_OPTIONAL);
SetProperty(DBPROP_INDEX_FILLFACTOR, DBPROPSET_INDEX, &m_cPropSets, &m_rgPropSets, (void*)50, DBTYPE_I4, DBPROPOPTIONS_OPTIONAL);
SetSettableProperty(DBPROP_INDEX_CLUSTERED, DBPROPSET_INDEX, &m_cPropSets, &m_rgPropSets); //VARIANT_TRUE, REQUIRED.
TEST2C_(hr = AlterIndex(m_pIndexID, &dbidNew), S_OK, DB_S_ERRORSOCCURRED)
CLEANUP:
Refresh_m_pIndexID(hr, dbidNew);
FreeProperties(&m_cPropSets, &m_rgPropSets);
TRETURN
}
// }} TCW_VAR_PROTOTYPE_END
// {{ TCW_VAR_PROTOTYPE(14)
//*-----------------------------------------------------------------------
// @mfunc General - Change index name and props (OPTIONAL)
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCAI_SingCol::Variation_14()
{
TBEGIN
HRESULT hr;
CDBID dbidNew(DBKIND_NAME, L"LoisLaneYYY");
//Set 2 props as optional. Also set a 3rd prop if it is settable.
//Set a non-index property optional.
SetProperty(DBPROP_INDEX_UNIQUE, DBPROPSET_INDEX, &m_cPropSets, &m_rgPropSets, (void*)VARIANT_TRUE, DBTYPE_BOOL, DBPROPOPTIONS_OPTIONAL);
SetProperty(DBPROP_INDEX_FILLFACTOR, DBPROPSET_INDEX, &m_cPropSets, &m_rgPropSets, (void*)50, DBTYPE_I4, DBPROPOPTIONS_OPTIONAL);
SetSettableProperty(DBPROP_INDEX_CLUSTERED, DBPROPSET_INDEX, &m_cPropSets, &m_rgPropSets); //VARIANT_TRUE, REQUIRED.
SetProperty(DBPROP_BOOKMARKS, DBPROPSET_ROWSET, &m_cPropSets, &m_rgPropSets, (void*)VARIANT_TRUE, DBTYPE_BOOL, DBPROPOPTIONS_OPTIONAL);
TESTC_(hr = AlterIndex(m_pIndexID, &dbidNew), DB_S_ERRORSOCCURRED)
CLEANUP:
Refresh_m_pIndexID(hr, dbidNew);
FreeProperties(&m_cPropSets, &m_rgPropSets);
TRETURN
}
// }} TCW_VAR_PROTOTYPE_END
// {{ TCW_VAR_PROTOTYPE(15)
//*-----------------------------------------------------------------------
// @mfunc General - Change index name and props (SETIFCHEAP)
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCAI_SingCol::Variation_15()
{
TBEGIN
HRESULT hr;
CDBID dbidNew(DBKIND_NAME, L"LoisLaneZZZ");
//Set 2 props as optional. Also set a 3rd prop if it is settable.
//Set a non-index property SETIFCHEAP.
// Note that DBPROPOPTIONS_OPTIONAL and DBPROPOPTIONS_SETIFCHEAP are numerically identical
TESTC(DBPROPOPTIONS_OPTIONAL == DBPROPOPTIONS_SETIFCHEAP);
SetProperty(DBPROP_INDEX_UNIQUE, DBPROPSET_INDEX, &m_cPropSets, &m_rgPropSets, (void*)VARIANT_TRUE, DBTYPE_BOOL, DBPROPOPTIONS_OPTIONAL);
SetProperty(DBPROP_INDEX_FILLFACTOR, DBPROPSET_INDEX, &m_cPropSets, &m_rgPropSets, (void*)50, DBTYPE_I4, DBPROPOPTIONS_OPTIONAL);
SetSettableProperty(DBPROP_INDEX_CLUSTERED, DBPROPSET_INDEX, &m_cPropSets, &m_rgPropSets); //VARIANT_TRUE, REQUIRED.
SetProperty(DBPROP_BOOKMARKS, DBPROPSET_ROWSET, &m_cPropSets, &m_rgPropSets, (void*)VARIANT_TRUE, DBTYPE_BOOL, DBPROPOPTIONS_SETIFCHEAP);
TESTC_(hr = AlterIndex(m_pIndexID, &dbidNew), DB_S_ERRORSOCCURRED)
CLEANUP:
Refresh_m_pIndexID(hr, dbidNew);
FreeProperties(&m_cPropSets, &m_rgPropSets);
TRETURN
}
// }} TCW_VAR_PROTOTYPE_END
// {{ TCW_VAR_PROTOTYPE(16)
//*-----------------------------------------------------------------------
// @mfunc General - try to set some index and some non-index props.
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCAI_SingCol::Variation_16()
{
TBEGIN
HRESULT hr;
CDBID dbidNew(DBKIND_NAME, L"SupermanSSS");
//Set 2 props as optional. Also set a 3rd prop if it is settable.
//Set a non-index property.
SetProperty(DBPROP_INDEX_UNIQUE, DBPROPSET_INDEX, &m_cPropSets, &m_rgPropSets, (void*)VARIANT_TRUE, DBTYPE_BOOL, DBPROPOPTIONS_OPTIONAL);
SetSettableProperty(DBPROP_INDEX_FILLFACTOR, DBPROPSET_INDEX, &m_cPropSets, &m_rgPropSets, (void*)50, DBTYPE_I4, DBPROPOPTIONS_OPTIONAL);
SetSettableProperty(DBPROP_INDEX_CLUSTERED, DBPROPSET_INDEX, &m_cPropSets, &m_rgPropSets); //VARIANT_TRUE, REQUIRED.
SetProperty(DBPROP_BOOKMARKS, DBPROPSET_ROWSET, &m_cPropSets, &m_rgPropSets); //VARIANT_TRUE, REQUIRED.
TESTC_(hr = AlterIndex(m_pIndexID, &dbidNew), DB_E_ERRORSOCCURRED)
CLEANUP:
Refresh_m_pIndexID(hr, dbidNew);
FreeProperties(&m_cPropSets, &m_rgPropSets);
TRETURN
}
// }} TCW_VAR_PROTOTYPE_END
// {{ TCW_VAR_PROTOTYPE(17)
//*-----------------------------------------------------------------------
// @mfunc General - pNewIndexID is NULL, set some props
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCAI_SingCol::Variation_17()
{
TBEGIN
HRESULT hr;
//Set 2 props as optional. Also set a 3rd prop if it is
//settable.
SetProperty(DBPROP_INDEX_UNIQUE, DBPROPSET_INDEX, &m_cPropSets, &m_rgPropSets, (void*)VARIANT_TRUE, DBTYPE_BOOL, DBPROPOPTIONS_OPTIONAL);
SetSettableProperty(DBPROP_INDEX_FILLFACTOR, DBPROPSET_INDEX, &m_cPropSets, &m_rgPropSets, (void*)50, DBTYPE_I4, DBPROPOPTIONS_OPTIONAL);
SetSettableProperty(DBPROP_INDEX_NULLS, DBPROPSET_INDEX, &m_cPropSets, &m_rgPropSets, (void*)DBPROPVAL_IN_DISALLOWNULL, DBTYPE_I4, DBPROPOPTIONS_OPTIONAL);
SetSettableProperty(DBPROP_INDEX_CLUSTERED, DBPROPSET_INDEX, &m_cPropSets, &m_rgPropSets); //VARIANT_TRUE, REQUIRED.
TESTC_(hr = AlterIndex(m_pIndexID, NULL), S_OK)
CLEANUP:
FreeProperties(&m_cPropSets, &m_rgPropSets);
TRETURN
}
// }} TCW_VAR_PROTOTYPE_END
// {{ TCW_VAR_PROTOTYPE(18)
//*-----------------------------------------------------------------------
// @mfunc General - pNewIndexID is same as pIndexID, set some props
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCAI_SingCol::Variation_18()
{
TBEGIN
HRESULT hr;
//Set 2 props as optional. Also set a 3rd prop if it is settable.
SetProperty(DBPROP_INDEX_UNIQUE, DBPROPSET_INDEX, &m_cPropSets, &m_rgPropSets, (void*)VARIANT_TRUE, DBTYPE_BOOL, DBPROPOPTIONS_OPTIONAL);
SetProperty(DBPROP_INDEX_FILLFACTOR, DBPROPSET_INDEX, &m_cPropSets, &m_rgPropSets, (void*)50, DBTYPE_I4, DBPROPOPTIONS_OPTIONAL);
SetSettableProperty(DBPROP_INDEX_CLUSTERED, DBPROPSET_INDEX, &m_cPropSets, &m_rgPropSets); //VARIANT_TRUE, REQUIRED.
TESTC_(hr = AlterIndex(m_pIndexID, m_pIndexID), S_OK)
CLEANUP:
FreeProperties(&m_cPropSets, &m_rgPropSets);
TRETURN
}
// }} TCW_VAR_PROTOTYPE_END
// {{ TCW_VAR_PROTOTYPE(19)
//*-----------------------------------------------------------------------
// @mfunc General - pNewIndexID is NULL, no props
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCAI_SingCol::Variation_19()
{
TBEGIN
HRESULT hr;
TESTC_(hr = AlterIndex(m_pIndexID, NULL), S_OK)
CLEANUP:
TRETURN
}
// }} TCW_VAR_PROTOTYPE_END
// {{ TCW_VAR_PROTOTYPE(20)
//*-----------------------------------------------------------------------
// @mfunc General - AlterIndex for all data types that can have indexes
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCAI_SingCol::Variation_20()
{
TBEGIN
HRESULT hr, hrCreateIndex;
CDBID dbidNew(DBKIND_NAME, L"SingCol");
DBID *pIndexID = NULL;
DBORDINAL cCols = 1;
DBINDEXCOLUMNDESC *pIndexColumnDesc = NULL;
DBPROPSET* prgPropSets = NULL;
DBID *pIndexWithProp = NULL;
HRESULT hrExpected = E_FAIL;
// TODO: Create unique index name?
cCols = m_cIndexColumnDesc;
// Initialize pIndexColumnDesc
SAFE_ALLOC(pIndexColumnDesc, DBINDEXCOLUMNDESC, cCols);
memset(pIndexColumnDesc, 0, (size_t)(sizeof(DBINDEXCOLUMNDESC)*cCols));
// There should be at least one column that can obtain an index with no props
TESTC_(hrCreateIndex = CreateIndex(&(m_pTable->GetTableID()), NULL, cCols,
pIndexColumnDesc, 0, NULL, &pIndexID), S_OK);
while(hrCreateIndex == S_OK)
{
// Find out if the property requested is valid for this index
// by attempting to create with the prop.
hrExpected = m_pIIndexDef->CreateIndex(&(m_pTable->GetTableID()), NULL, cCols,
pIndexColumnDesc, m_cPropSets, m_rgPropSets, &pIndexWithProp);
// We should get S_OK or DB_E_ERRORSOCCURRED for required prop
if (hrExpected != DB_E_ERRORSOCCURRED)
CHECK(hrExpected, S_OK);
// Drop the property index
CHECK(m_pIIndexDef->DropIndex(&(m_pTable->GetTableID()), pIndexWithProp), S_OK);
ReleaseDBID(pIndexWithProp);
pIndexWithProp = NULL;
// Now alter the index to obtain a new name and the prop desired.
hr = AlterIndex(pIndexID, &dbidNew);
CHECK(hr, hrExpected);
if (SUCCEEDED(hr))
{
// Drop the altered index
CHECK(m_pIIndexDef->DropIndex(&(m_pTable->GetTableID()), &dbidNew), S_OK);
}
else
{
// Drop the previous index
CHECK(m_pIIndexDef->DropIndex(&(m_pTable->GetTableID()), pIndexID), S_OK);
}
// Now drop both indexes again in case the provider lied about the success of
// AlterIndex (one does). Don't check return code in case it didn't lie.
m_pIIndexDef->DropIndex(&(m_pTable->GetTableID()), &dbidNew);
m_pIIndexDef->DropIndex(&(m_pTable->GetTableID()), pIndexID);
ReleaseDBID(pIndexID);
pIndexID = NULL;
// Get the next possible index
hrCreateIndex = CreateIndex(&(m_pTable->GetTableID()), NULL, cCols,
pIndexColumnDesc, m_cPropSets, m_rgPropSets, &pIndexID, TRUE);
}
CLEANUP:
CleanUpIndex(&(m_pTable->GetTableID()), &pIndexID, pIndexColumnDesc, &m_cPropSets, &m_rgPropSets);
TRETURN
}
// }} TCW_VAR_PROTOTYPE_END
// {{ TCW_VAR_PROTOTYPE(21)
//*-----------------------------------------------------------------------
// @mfunc General - Create several indexes and alter each
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCAI_SingCol::Variation_21()
{
TBEGIN
HRESULT hr, hrCreateIndex;
DBID *pIndexID = NULL;
ULONG iCol;
DBORDINAL cCols = 1;
DBORDINAL cTableCols = 1;
DBORDINAL cIndexes = 1;
DBINDEXCOLUMNDESC *pIndexColumnDesc = NULL;
DBPROPSET* prgPropSets = NULL;
DBID *pIndexWithProp = NULL;
HRESULT hrExpected = S_OK;
DBID * pIndexIDs = NULL;
WCHAR wszName[]=L"AI00000000";
CDBID dbidNew(DBKIND_NAME, (LPWSTR)wszName);
// Count number of columns in the table
cTableCols = m_pTable->CountColumnsOnTable();
cCols = m_cIndexColumnDesc;
// Combinations (or permutations?) of N columns taken L at at time is
// N!/(N-L)!
for (iCol = 0; iCol < cCols; iCol++)
cIndexes *= cTableCols - iCol;
// Allocate space for a DBID for each column to hold the created index id
SAFE_ALLOC(pIndexIDs, DBID, cIndexes);
// Initialize pIndexColumnDesc
SAFE_ALLOC(pIndexColumnDesc, DBINDEXCOLUMNDESC, cCols);
memset(pIndexColumnDesc, 0, (size_t)(sizeof(DBINDEXCOLUMNDESC)*cCols));
// Reset to 0 indexes
cIndexes = 0;
// There should be at least one column that can obtain an index with no props
TESTC_PROVIDER(S_OK == (hrCreateIndex = CreateIndex(&(m_pTable->GetTableID()), NULL, cCols,
pIndexColumnDesc, 0, NULL, &pIndexID)));
while(hrCreateIndex == S_OK)
{
// Save this index id
DuplicateDBID(*pIndexID, &pIndexIDs[cIndexes]);
if (m_cPropSets)
{
// Find out if the property requested is valid for this index
// by attempting to create with the prop.
hrExpected = m_pIIndexDef->CreateIndex(&(m_pTable->GetTableID()), NULL, cCols,
pIndexColumnDesc, m_cPropSets, m_rgPropSets, &pIndexWithProp);
// We should get S_OK or DB_E_ERRORSOCCURRED for required prop
if (hrExpected == E_FAIL)
// Some providers will return E_FAIL if too many indexes on one table,
// usually >250, but since we don't know if this is valid we need to
// warn. We will arbitrarily pick a point at which to warn.
if (cIndexes > 30)
CHECKW(hrExpected, S_OK);
else
CHECK(hrExpected, S_OK);
else if (hrExpected == DB_E_ERRORSOCCURRED)
// It was DB_E_ERRORSOCCURRED, must have at least one prop
COMPARE(m_cPropSets > 0, TRUE);
else
CHECK(hrExpected, S_OK);
// Drop the property index
if (SUCCEEDED(hrExpected))
{
CHECK(m_pIIndexDef->DropIndex(&(m_pTable->GetTableID()), pIndexWithProp), S_OK);
ReleaseDBID(pIndexWithProp);
pIndexWithProp = NULL;
}
}
// Make a unique new name
swprintf(dbidNew.uName.pwszName+sizeof(L"AI"), L"%u", cIndexes);
// Now alter the index to obtain a new name and the prop desired.
CHECK(hr = AlterIndex(pIndexID, &dbidNew), hrExpected);
ReleaseDBID(pIndexID);
pIndexID = NULL;
if (SUCCEEDED(hr))
{
ReleaseDBID(&pIndexIDs[cIndexes], FALSE);
DuplicateDBID(dbidNew, &pIndexIDs[cIndexes]);
}
// Get the next possible index with no props
hrCreateIndex = CreateIndex(&(m_pTable->GetTableID()), NULL, cCols,
pIndexColumnDesc, 0, NULL, &pIndexID, TRUE);
cIndexes++;
}
odtLog << L"Created " << cIndexes << L" indexes.\n";
CLEANUP:
// Drop all the indexes created
for (ULONG iIndex = 0; iIndex < cIndexes; iIndex++)
{
CHECK(m_pIIndexDef->DropIndex(&(m_pTable->GetTableID()), &pIndexIDs[iIndex]), S_OK);
ReleaseDBID(&pIndexIDs[iIndex], FALSE);
}
SAFE_FREE(pIndexIDs);
if (pIndexID)
{
CHECK(m_pIIndexDef->DropIndex(&(m_pTable->GetTableID()), pIndexID), S_OK);
ReleaseDBID(pIndexID);
}
SAFE_FREE(pIndexColumnDesc);
TRETURN
}
// }} TCW_VAR_PROTOTYPE_END
// {{ TCW_VAR_PROTOTYPE(22)
//*-----------------------------------------------------------------------
// @mfunc General - AlterIndex on multiple threads, same index
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCAI_SingCol::Variation_22()
{
// Call AlterIndex from multiple threads on the same index. One should
// succeed, the others should fail.
ULONG iThrd, iWon;
BOOL fExists = FALSE;
HRESULT hrThreads[MAX_THREADS];
ULONG cWon = 0;
// We'll have a different index name for each thread.
LPWSTR pwszIndexNameRoot = L"Idx00000";
TBEGIN
INIT_THREADS(MAX_THREADS);
//Setup Thread Arguments
THREADARG6 TArgs[MAX_THREADS];
// Create the index names to be used
memset(TArgs, 0, MAX_THREADS*sizeof(THREADARG6));
for (iThrd = 0; iThrd < MAX_THREADS; iThrd++)
{
DBID * pIndexID = NULL;
// Allocate a DBID buffer
SAFE_ALLOC(pIndexID, DBID, 1);
(*pIndexID).eKind = DBKIND_NAME;
(*pIndexID).uName.pwszName = wcsDuplicate(pwszIndexNameRoot);
TESTC((*pIndexID).uName.pwszName != NULL);
// Change this name to a unique one
_ltow(iThrd, (*pIndexID).uName.pwszName+wcslen(L"Idx"), 10);
// Set the hresult for this thread to failure
hrThreads[iThrd] = E_FAIL;
TArgs[iThrd].pFunc = m_pIAlterIndex; // IAlterIndex interface
TArgs[iThrd].pArg1 = &(m_pTable->GetTableIDRef()); // Table to alter
TArgs[iThrd].pArg2 = m_pIndexID; // Index to alter
TArgs[iThrd].pArg3 = pIndexID; // New name
TArgs[iThrd].pArg4 = &hrThreads[iThrd]; // Return code
TArgs[iThrd].pArg5 = 0; // Count of props to set
TArgs[iThrd].pArg6 = NULL; // Props to set
//Create the thread
CREATE_THREAD(iThrd, Thread_VerifyAlterIndex, &TArgs[iThrd]);
}
START_THREADS();
END_THREADS();
// See which thread won
for (iThrd = 0; iThrd < MAX_THREADS; iThrd++)
{
if (hrThreads[iThrd] == S_OK)
{
cWon++;
iWon = iThrd;
}
// Should succeed, or else if another thread beat it then DB_E_NOINDEX.
TEST2C_(hrThreads[iThrd], S_OK, DB_E_NOINDEX);
}
// Only one thread should have won
TESTC(cWon == 1);
// And the appropriate index name should exist
TESTC_(DoesIndexExist(&(m_pTable->GetTableID()), (DBID *)(TArgs[iWon].pArg3), &fExists), S_OK);
TESTC(fExists);
// Update the current index id
Refresh_m_pIndexID(S_OK, *(DBID *)(TArgs[iWon].pArg3));
CLEANUP:
// Release DBID memory
for (iThrd=0; iThrd < MAX_THREADS; iThrd++)
ReleaseDBID((DBID *)(TArgs[iThrd].pArg3));
TRETURN
}
// }} TCW_VAR_PROTOTYPE_END
// {{ TCW_VAR_PROTOTYPE(23)
//*-----------------------------------------------------------------------
// @mfunc General - AlterIndex on multiple threads, different indexes
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCAI_SingCol::Variation_23()
{
// Call AlterIndex from multiple threads on different indexes. All should
// succeed.
ULONG iThrd;
BOOL fExists = FALSE;
HRESULT hrThreads[MAX_THREADS];
ULONG cWon = 0;
ULONG cCols = 1;
DBINDEXCOLUMNDESC *pIndexColumnDesc = NULL;
// We'll have a different index name for each thread.
LPWSTR pwszIndexNameRoot = L"Idx00000";
TBEGIN
INIT_THREADS(MAX_THREADS);
//Setup Thread Arguments
THREADARG6 TArgs[MAX_THREADS];
// Initialize pIndexColumnDesc
SAFE_ALLOC(pIndexColumnDesc, DBINDEXCOLUMNDESC, cCols);
memset(pIndexColumnDesc, 0, sizeof(DBINDEXCOLUMNDESC)*cCols);
// Create the index names to be used
memset(TArgs, 0, MAX_THREADS*sizeof(THREADARG6));
for (iThrd = 0; iThrd < MAX_THREADS; iThrd++)
{
DBID * pIndexID = NULL;
DBID * pNewIndexID = NULL;
TESTC_(CreateIndex(&(m_pTable->GetTableID()), NULL, cCols,
pIndexColumnDesc, 0, NULL, &pIndexID), S_OK);
// Allocate a DBID buffer
SAFE_ALLOC(pNewIndexID, DBID, 1);
(*pNewIndexID).eKind = DBKIND_NAME;
(*pNewIndexID).uName.pwszName = wcsDuplicate(pwszIndexNameRoot);
TESTC((*pNewIndexID).uName.pwszName != NULL);
// Change this name to a unique one
_ltow(iThrd, (*pNewIndexID).uName.pwszName+wcslen(L"Idx"), 10);
// Set the hresult for this thread to failure
hrThreads[iThrd] = E_FAIL;
TArgs[iThrd].pFunc = m_pIAlterIndex; // IAlterIndex interface
TArgs[iThrd].pArg1 = &(m_pTable->GetTableIDRef()); // Table to alter
TArgs[iThrd].pArg2 = pIndexID; // Index to alter
TArgs[iThrd].pArg3 = pNewIndexID; // New name
TArgs[iThrd].pArg4 = &hrThreads[iThrd]; // Return code
TArgs[iThrd].pArg5 = 0; // Count of props to set
TArgs[iThrd].pArg6 = NULL; // Props to set
//Create the thread
CREATE_THREAD(iThrd, Thread_VerifyAlterIndex, &TArgs[iThrd]);
}
START_THREADS();
END_THREADS();
// All threads should succeed
for (iThrd = 0; iThrd < MAX_THREADS; iThrd++)
{
// Should succeed, or else if another thread beat it then DB_E_NOINDEX.
TESTC_(hrThreads[iThrd], S_OK);
// And the appropriate index name should exist
TESTC_(DoesIndexExist(&(m_pTable->GetTableID()), (DBID *)(TArgs[iThrd].pArg3), &fExists), S_OK);
TESTC(fExists);
// Drop the index
TESTC_(m_pIIndexDef->DropIndex(&(m_pTable->GetTableID()), (DBID *)(TArgs[iThrd].pArg3)), S_OK);
}
CLEANUP:
// Release DBID memory
for (iThrd=0; iThrd < MAX_THREADS; iThrd++)
{
ReleaseDBID((DBID *)(TArgs[iThrd].pArg2));
ReleaseDBID((DBID *)(TArgs[iThrd].pArg3));
}
SAFE_FREE(pIndexColumnDesc);
TRETURN
}
// }} TCW_VAR_PROTOTYPE_END
// {{ TCW_VAR_PROTOTYPE(24)
//*-----------------------------------------------------------------------
// @mfunc General - AlterIndex on multiple threads, two tables to same index name
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCAI_SingCol::Variation_24()
{
// Both should succeed
ULONG iThrd, iTime;
HRESULT hrThreads[TWO_THREADS];
ULONG cCols = 1;
DBINDEXCOLUMNDESC *pIndexColumnDesc = NULL;
DBID * pTableFirst = &(m_pTable->GetTableIDRef());
DBID * pTableSecond = &(m_pNoNullTable->GetTableIDRef());
DBID * pIndexIDFirst = NULL;
DBID * pIndexIDSecond = NULL;
CDBID dbid(DBKIND_NAME, L"Idx00001");
TBEGIN
INIT_THREADS(TWO_THREADS);
//Setup Thread Arguments
THREADARG6 TArgs[TWO_THREADS];
// Initialize pIndexColumnDesc
SAFE_ALLOC(pIndexColumnDesc, DBINDEXCOLUMNDESC, cCols);
memset(pIndexColumnDesc, 0, sizeof(DBINDEXCOLUMNDESC)*cCols);
for (iTime = 0; iTime < 10; iTime++)
{
// Create the indexes to be altered
TESTC_(CreateIndex(pTableFirst, NULL, cCols,
pIndexColumnDesc, 0, NULL, &pIndexIDFirst), S_OK);
TESTC_(CreateIndex(pTableSecond, NULL, cCols,
pIndexColumnDesc, 0, NULL, &pIndexIDSecond), S_OK);
// Set up the first thread args
hrThreads[0] = E_FAIL;
TArgs[0].pFunc = m_pIAlterIndex; // IAlterIndex interface
TArgs[0].pArg1 = pTableFirst; // Table to alter
TArgs[0].pArg2 = pIndexIDFirst; // Index to alter
TArgs[0].pArg3 = &dbid; // New name
TArgs[0].pArg4 = &hrThreads[0]; // Return code
TArgs[0].pArg5 = 0; // Count of props to set
TArgs[0].pArg6 = NULL; // Props to set
//Create the thread
CREATE_THREAD(0, Thread_VerifyAlterIndex, &TArgs[0]);
// Set up the second thread args
hrThreads[1] = E_FAIL;
TArgs[1].pFunc = m_pIAlterIndex; // IAlterIndex interface
TArgs[1].pArg1 = pTableSecond; // Table to alter
TArgs[1].pArg2 = pIndexIDSecond; // Index to alter
TArgs[1].pArg3 = &dbid; // New name
TArgs[1].pArg4 = &hrThreads[1]; // Return code
TArgs[1].pArg5 = 0; // Count of props to set
TArgs[1].pArg6 = NULL; // Props to set
//Create the thread
CREATE_THREAD(1, Thread_VerifyAlterIndex, &TArgs[1]);
START_THREADS();
END_THREADS();
// See whether the threads succeeded or failed
for (iThrd = 0; iThrd < TWO_THREADS; iThrd++)
{
BOOL fExists = FALSE;
// Should succeed
TESTC_(hrThreads[iThrd], S_OK);
TESTC_(DoesIndexExist((DBID *)(TArgs[iThrd].pArg1), (DBID *)(TArgs[iThrd].pArg3), &fExists), S_OK);
// And the appropriate index name should exist
if (hrThreads[iThrd] == S_OK)
{
TESTC(fExists);
// Drop the new index
TESTC_(m_pIIndexDef->DropIndex((DBID *)(TArgs[iThrd].pArg1), (DBID *)(TArgs[iThrd].pArg3)), S_OK);
}
else
{
TESTC(!fExists);
// Drop the old index
TESTC_(m_pIIndexDef->DropIndex((DBID *)(TArgs[iThrd].pArg1), (DBID *)(TArgs[iThrd].pArg2)), S_OK);
}
}
ReleaseDBID(pIndexIDFirst);
pIndexIDFirst= NULL;
ReleaseDBID(pIndexIDSecond);
pIndexIDSecond = NULL;
} // Next time
CLEANUP:
odtLog << L"Times: " << iTime << L"\n";
SAFE_FREE(pIndexColumnDesc);
TRETURN
}
// }} TCW_VAR_PROTOTYPE_END
// {{ TCW_VAR_PROTOTYPE(25)
//*-----------------------------------------------------------------------
// @mfunc General - AlterIndex on multiple threads, name on one, props on another
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCAI_SingCol::Variation_25()
{
// Both should succeed, or, props should fail if beaten by name change
ULONG iThrd;
HRESULT hrThreads[TWO_THREADS];
ULONG cCols = 1;
DBINDEXCOLUMNDESC *pIndexColumnDesc = NULL;
DBID * pTable = &(m_pNoNullTable->GetTableIDRef());
DBID * pIndexID = NULL;
CDBID dbid(DBKIND_NAME, L"Idx00001");
TBEGIN
INIT_THREADS(TWO_THREADS);
//Setup Thread Arguments
THREADARG6 TArgs[TWO_THREADS];
// Initialize pIndexColumnDesc
SAFE_ALLOC(pIndexColumnDesc, DBINDEXCOLUMNDESC, cCols);
memset(pIndexColumnDesc, 0, sizeof(DBINDEXCOLUMNDESC)*cCols);
// Set Primary Key prop as it's the most prevalent
TESTC(m_cPropSets == 0);
SetSettableProperty(DBPROP_INDEX_PRIMARYKEY, DBPROPSET_INDEX, &m_cPropSets, &m_rgPropSets, (void*)VARIANT_TRUE, DBTYPE_BOOL, DBPROPOPTIONS_REQUIRED);
// Create the index to be altered
TESTC_PROVIDER(S_OK == CreateAlterableIndex(pTable, NULL, m_cIndexColumnDesc,
pIndexColumnDesc, m_cPropSets, m_rgPropSets, &pIndexID));
// Set up the first thread args
hrThreads[0] = E_FAIL;
TArgs[0].pFunc = m_pIAlterIndex; // IAlterIndex interface
TArgs[0].pArg1 = pTable; // Table to alter
TArgs[0].pArg2 = pIndexID; // Index to alter
TArgs[0].pArg3 = pIndexID; // New name same as old name
TArgs[0].pArg4 = &hrThreads[0]; // Return code
TArgs[0].pArg5 = (LPVOID)(ULONG_PTR)m_cPropSets;// Count of props to set
TArgs[0].pArg6 = (LPVOID)m_rgPropSets; // Props to set
//Create the thread
CREATE_THREAD(0, Thread_VerifyAlterIndex, &TArgs[0]);
// Set up the second thread args
hrThreads[1] = E_FAIL;
TArgs[1].pFunc = m_pIAlterIndex; // IAlterIndex interface
TArgs[1].pArg1 = pTable; // Table to alter
TArgs[1].pArg2 = pIndexID; // Index to alter
TArgs[1].pArg3 = &dbid; // New name
TArgs[1].pArg4 = &hrThreads[1]; // Return code
TArgs[1].pArg5 = (LPVOID)0; // Count of props to set
TArgs[1].pArg6 = NULL; // Props to set
//Create the thread
CREATE_THREAD(1, Thread_VerifyAlterIndex, &TArgs[1]);
START_THREADS();
END_THREADS();
// See whether the threads succeeded or failed
for (iThrd = 0; iThrd < TWO_THREADS; iThrd++)
{
BOOL fExists = FALSE;
// Prop thread may succeed, or fail if beaten by name change
if (iThrd == 0)
{
TEST2C_(hrThreads[iThrd], S_OK, DB_E_NOINDEX);
}
else
{
// Name change must always succeed
TESTC_(hrThreads[iThrd], S_OK);
}
TESTC_(DoesIndexExist((DBID *)(TArgs[iThrd].pArg1), (DBID *)(TArgs[iThrd].pArg3), &fExists), S_OK);
// And the appropriate index name should exist
if (iThrd == 1 && hrThreads[iThrd] == S_OK)
{
TESTC(fExists);
// Drop the new index
TESTC_(m_pIIndexDef->DropIndex((DBID *)(TArgs[iThrd].pArg1), (DBID *)(TArgs[iThrd].pArg3)), S_OK);
}
else
{
// The old index cannot exist
TESTC(!fExists);
}
}
CLEANUP:
ReleaseDBID(pIndexID);
pIndexID= NULL;
FreeProperties(&m_cPropSets, &m_rgPropSets);
SAFE_FREE(pIndexColumnDesc);
TRETURN
}
// }} TCW_VAR_PROTOTYPE_END
// {{ TCW_VAR_PROTOTYPE(26)
//*-----------------------------------------------------------------------
// @mfunc General - AlterIndex on index created by command
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCAI_SingCol::Variation_26()
{
TBEGIN
HRESULT hr;
ULONG iCol, iCCol;
ULONG rgIndexCols[MAX_INDEX_COLS];
ULONG * prgIndexCols = rgIndexCols;
CDBID dbidNew(DBKIND_NAME, BuildValidName(m_cMaxIndexName, L"ABC"));
CDBID dbidOld(DBKIND_NAME, BuildValidName(m_cMaxIndexName, L"XYZ"));
// Get the column numbers for the index
for (iCol = 0; iCol < m_cIndexColumnDesc; iCol++)
{
// Find the matching CCol DBID
for (iCCol = 1; iCCol <= m_pTable->CountColumnsOnTable(); iCCol++)
{
CCol TempCol;
TESTC_(m_pTable->GetColInfo(iCCol, TempCol), S_OK);
// if this DBID matched the index col DBID then this is the right col
if (CompareDBID(*(m_pIndexColumnDesc[iCol].pColumnID),
*TempCol.GetColID(), m_pThisTestModule->m_pIUnknown))
break;
}
// We *must* find the matching DBID
TESTC(iCCol < m_pTable->CountColumnsOnTable());
// Insert column number in array
rgIndexCols[iCol] = iCCol;
}
// Create an index with a command. Just to be different use descending index.
TESTC_(m_pTable->ExecuteCommand(CREATE_INDEX_DESC, IID_NULL, dbidOld.uName.pwszName,
NULL, &m_cIndexColumnDesc, (DB_LORDINAL **)&prgIndexCols), S_OK);
// Alter the index
TESTC_(hr = AlterIndex(&dbidOld, &dbidNew), S_OK);
// Drop the index
TESTC_(m_pIIndexDef->DropIndex(&(m_pTable->GetTableID()), &dbidNew), S_OK);
CLEANUP:
SAFE_FREE(dbidOld.uName.pwszName);
SAFE_FREE(dbidNew.uName.pwszName);
TRETURN
}
// }} TCW_VAR_PROTOTYPE_END
// {{ TCW_VAR_PROTOTYPE(27)
//*-----------------------------------------------------------------------
// @mfunc General - AlterIndex with quoted name
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCAI_SingCol::Variation_27()
{
TBEGIN
HRESULT hr;
LPWSTR pwszNewIndexName = BuildValidName(m_cMaxIndexName, L"XYZ");
LPWSTR pwszTableName = (&(m_pTable->GetTableID()))->uName.pwszName;
LPWSTR pwszIndexName = m_pIndexID->uName.pwszName;
LPWSTR pwszQuotedTableName = NULL;
LPWSTR pwszQuotedIndexName = NULL;
LPWSTR pwszQuotedNewIndexName = NULL;
// Get quoted table name
TESTC_(m_pTable->GetQuotedName(pwszTableName,&pwszQuotedTableName), S_OK);
// Get quoted current index name
TESTC_(m_pTable->GetQuotedName(pwszIndexName,&pwszQuotedIndexName), S_OK);
// Get quoted new index name
TESTC_(m_pTable->GetQuotedName(pwszNewIndexName,&pwszQuotedNewIndexName), S_OK);
// Set the names into the dbid's
{
CDBID dbidNew(DBKIND_NAME, pwszQuotedNewIndexName);
CDBID dbidNewUnquoted(DBKIND_NAME, pwszNewIndexName);
CDBID dbidOld(DBKIND_NAME, pwszQuotedIndexName);
CDBID dbidTable(DBKIND_NAME, pwszQuotedTableName);
BOOL fExists = FALSE;
// Call AlterIndex. Note our helper function can't handle quoted or qualified
// names, so we have to call directly.
TESTC_(hr = m_pIAlterIndex->AlterIndex(&dbidTable, &dbidOld, &dbidNew, 0, NULL), S_OK)
// Since we didn't use our helper we have to check index existence ourself.
TESTC_(DoesIndexExist(&(m_pTable->GetTableID()), &dbidNewUnquoted, &fExists), S_OK);
TESTC(fExists == TRUE);
Refresh_m_pIndexID(hr, dbidNewUnquoted);
TESTC_(hr, S_OK);
}
CLEANUP:
SAFE_FREE(pwszNewIndexName);
SAFE_FREE(pwszQuotedTableName);
SAFE_FREE(pwszQuotedIndexName);
SAFE_FREE(pwszQuotedNewIndexName);
TRETURN
}
// }} TCW_VAR_PROTOTYPE_END
// {{ TCW_VAR_PROTOTYPE(28)
//*-----------------------------------------------------------------------
// @mfunc General - AlterIndex with qualified and quoted name
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCAI_SingCol::Variation_28()
{
TBEGIN
HRESULT hr;
LPWSTR pwszNewIndexName = BuildValidName(m_cMaxIndexName, L"XYZ");
LPWSTR pwszTableName = (&(m_pTable->GetTableID()))->uName.pwszName;
LPWSTR pwszIndexName = m_pIndexID->uName.pwszName;
LPWSTR pwszCatalogName = NULL;
LPWSTR pwszSchemaName = NULL;
LPWSTR pwszQualifiedTableName = NULL;
LPWSTR pwszQualifiedIndexName = NULL;
LPWSTR pwszQualifiedNewIndexName = NULL;
TESTC(GetQualifierNames(m_pThisTestModule->m_pIUnknown2, pwszTableName,
&pwszCatalogName, &pwszSchemaName));
// Get Qualified table name
TESTC_(m_pTable->GetQualifiedName(pwszCatalogName, pwszSchemaName,
pwszTableName,&pwszQualifiedTableName), S_OK);
// Get Qualified current index name
TESTC_(m_pTable->GetQualifiedName(pwszCatalogName, pwszSchemaName,
pwszIndexName,&pwszQualifiedIndexName), S_OK);
// Get Qualified new index name
TESTC_(m_pTable->GetQualifiedName(pwszCatalogName, pwszSchemaName,
pwszNewIndexName,&pwszQualifiedNewIndexName), S_OK);
// Set the names into the dbid's
{
CDBID dbidNew(DBKIND_NAME, pwszQualifiedNewIndexName);
CDBID dbidNewUnQualified(DBKIND_NAME, pwszNewIndexName);
CDBID dbidOld(DBKIND_NAME, pwszQualifiedIndexName);
CDBID dbidTable(DBKIND_NAME, pwszQualifiedTableName);
BOOL fExists = FALSE;
// Call AlterIndex. Note our helper function can't handle Qualified or qualified
// names, so we have to call directly.
TESTC_(hr = m_pIAlterIndex->AlterIndex(&dbidTable, &dbidOld, &dbidNew, 0, NULL), S_OK)
// Since we didn't use our helper we have to check index existence ourself.
TESTC_(DoesIndexExist(&(m_pTable->GetTableID()), &dbidNewUnQualified, &fExists), S_OK);
TESTC(fExists == TRUE);
Refresh_m_pIndexID(hr, dbidNewUnQualified);
TESTC_(hr, S_OK);
}
CLEANUP:
SAFE_FREE(pwszNewIndexName);
SAFE_FREE(pwszQualifiedTableName);
SAFE_FREE(pwszQualifiedIndexName);
SAFE_FREE(pwszQualifiedNewIndexName);
SAFE_FREE(pwszCatalogName);
SAFE_FREE(pwszSchemaName);
TRETURN
}
// }} TCW_VAR_PROTOTYPE_END
// {{ TCW_VAR_PROTOTYPE(29)
//*-----------------------------------------------------------------------
// @mfunc General - AlterIndex to same name as PrimaryKey constraint
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCAI_SingCol::Variation_29()
{
TBEGIN
HRESULT hr;
CDBID dbidNew(DBKIND_NAME, NULL);
DBID * pTableID = &(m_pNoNullTable->GetTableIDRef());
DBCOLUMNDESC * pColumnDesc = NULL;
DBPROPSET * pColPropSets = NULL;
ULONG cColPropSets = 0;
DBORDINAL cCols = m_pTable->CountColumnsOnTable();
ULONG iCol;
DBINDEXCOLUMNDESC *pIndexColumnDesc = NULL;
DBID * pIndexID = NULL;
CTable NewTable(m_pThisTestModule->m_pIUnknown2, (LPWSTR)gwszModuleName, NONULLS);
CIndexInfo IndexInfo;
LPWSTR pwszPK = NULL;
// Note we could just AlterTable on the current automaketable to create a
// PrimaryKey constraint, but at the time this was written AlterTable did not
// properly support this.
// Initialize pIndexColumnDesc
SAFE_ALLOC(pIndexColumnDesc, DBINDEXCOLUMNDESC, cCols);
memset(pIndexColumnDesc, 0, (size_t)(sizeof(DBINDEXCOLUMNDESC)*cCols));
// Get the DBCOLUMNDESC information from the automaketable
TESTC_(m_pTable->BuildColumnDescs(&pColumnDesc), S_OK);
// Create a primary key index on the automaketable so we can tell which column
// will support a primary key.
TESTC(m_cPropSets == 0);
SetSettableProperty(DBPROP_INDEX_PRIMARYKEY, DBPROPSET_INDEX, &m_cPropSets, &m_rgPropSets, (void*)VARIANT_TRUE, DBTYPE_BOOL, DBPROPOPTIONS_REQUIRED);
// Create the index to be altered
TESTC_PROVIDER(S_OK == CreateAlterableIndex(pTableID, NULL, m_cIndexColumnDesc,
pIndexColumnDesc, m_cPropSets, m_rgPropSets, &pIndexID));
// Drop the index on the automaketable - we only wanted the column descs
TESTC_(m_pIIndexDef->DropIndex(pTableID, pIndexID), S_OK);
ReleaseDBID(pIndexID);
// Add a PrimaryKey prop for this column for the new table
for (iCol = 0; iCol < cCols; iCol++)
{
if (CompareDBID(*pIndexColumnDesc[iCol].pColumnID, pColumnDesc[iCol].dbcid))
{
SetProperty(DBPROP_COL_PRIMARYKEY, DBPROPSET_COLUMN,
&pColumnDesc[iCol].cPropertySets, &pColumnDesc[iCol].rgPropertySets,
(void*)VARIANT_TRUE, DBTYPE_BOOL, DBPROPOPTIONS_REQUIRED);
break;
}
}
TESTC(iCol < cCols);
// Set the column desc info for the new table
TESTC(NewTable.SetColumnDesc(pColumnDesc, cCols) != NULL);
NewTable.SetBuildColumnDesc(FALSE);
// Create the new table
TESTC_(NewTable.CreateTable(MIN_TABLE_ROWS, 0), S_OK);
// Get information about the index if the provider created an index to support
// the primary key constraint
TESTC_PROVIDER(IndexInfo.Init(m_pIOpenRowset, &(NewTable.GetTableID()), NULL));
// Get the name of the PK index (the only index on the table at this point)
pwszPK = (LPWSTR)IndexInfo.GetIndexValuePtr(0, IS_INDEX_NAME);
TESTC(pwszPK != NULL);
// Set the name the same as the PK name
dbidNew.uName.pwszName = pwszPK;
// Free the props so we're not making a duplicate PK
FreeProperties(&m_cPropSets, &m_rgPropSets);
// Create an index on the new table, using the same column as above.
TESTC_PROVIDER(S_OK == CreateIndex(&(NewTable.GetTableID()),
NULL, m_cIndexColumnDesc,pIndexColumnDesc, 0, NULL,
&pIndexID));
// Call AlterIndex to set this name.
TESTC_(hr = AlterIndex(&(NewTable.GetTableID()), pIndexID, &dbidNew), DB_E_DUPLICATEINDEXID)
CLEANUP:
ReleaseDBID(pIndexID);
FreeProperties(&m_cPropSets, &m_rgPropSets);
SAFE_FREE(pIndexColumnDesc);
TRETURN
}
// }} TCW_VAR_PROTOTYPE_END
// {{ TCW_VAR_PROTOTYPE(30)
//*-----------------------------------------------------------------------
// @mfunc General - AlterIndex on temp table
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCAI_SingCol::Variation_30()
{
TBEGIN
HRESULT hr;
CDBID dbidNew(DBKIND_NAME, BuildValidName(m_cMaxTableName+1, L"IAlterIndex"));
DBID * pTableID = NULL;
DBCOLUMNDESC * pColumnDesc = NULL;
DBPROPSET * pColPropSets = NULL;
ULONG cColPropSets = 0;
DBORDINAL cCols = m_pTable->CountColumnsOnTable();
DBINDEXCOLUMNDESC *pIndexColumnDesc = NULL;
DBID * pIndexID = NULL;
CTable NewTable(m_pThisTestModule->m_pIUnknown2, (LPWSTR)gwszModuleName, NONULLS);
DBPROPSET * pTablePropSets = NULL;
ULONG cTablePropSets = 0;
// Note we could just AlterTable on the current automaketable to create a
// PrimaryKey constraint, but at the time this was written AlterTable did not
// properly support this.
// Set primary key prop
TESTC(m_cPropSets == 0);
SetSettableProperty(DBPROP_INDEX_PRIMARYKEY, DBPROPSET_INDEX, &m_cPropSets, &m_rgPropSets, (void*)VARIANT_TRUE, DBTYPE_BOOL, DBPROPOPTIONS_REQUIRED);
// Initialize pIndexColumnDesc
SAFE_ALLOC(pIndexColumnDesc, DBINDEXCOLUMNDESC, cCols);
memset(pIndexColumnDesc, 0, (size_t)(sizeof(DBINDEXCOLUMNDESC)*cCols));
// Get the DBCOLUMNDESC information from the automaketable
TESTC_(m_pTable->BuildColumnDescs(&pColumnDesc), S_OK);
// Change this table to be a temp table. Not all providers will support this
TESTC(SetProperty(DBPROP_TBL_TEMPTABLE, DBPROPSET_TABLE, &cTablePropSets, &pTablePropSets, (void*)VARIANT_TRUE, DBTYPE_BOOL, DBPROPOPTIONS_REQUIRED));
NewTable.SetPropertySets(pTablePropSets, cTablePropSets);
// Set the column desc info for the new table
TESTC(NewTable.SetColumnDesc(pColumnDesc, cCols) != NULL);
NewTable.SetDBID(&pTableID);
NewTable.SetBuildColumnDesc(FALSE);
NewTable.ResetInputTableID();
// Create the temp table
TESTC_PROVIDER(S_OK == NewTable.CreateTable(MIN_TABLE_ROWS, 0));
// Create an index on the new table, using the same column as above.
TESTC_PROVIDER(S_OK == CreateAlterableIndex(&(NewTable.GetTableID()),
NULL, m_cIndexColumnDesc, pIndexColumnDesc, m_cPropSets, m_rgPropSets,
&pIndexID));
// Call AlterIndex to set this name and props
TESTC_(hr = AlterIndex(&(NewTable.GetTableID()), pIndexID, &dbidNew), S_OK);
CLEANUP:
// We don't drop the index 'cause it's dropped when the table is dropped.
// Ditto for table props
FreeProperties(&m_cPropSets, &m_rgPropSets);
SAFE_FREE(pIndexColumnDesc);
TRETURN
}
// }} TCW_VAR_PROTOTYPE_END
// {{ TCW_VAR_PROTOTYPE(31)
//*-----------------------------------------------------------------------
// @mfunc General - pIndexID is DBKIND_GUID_NAME
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCAI_SingCol::Variation_31()
{
TBEGIN
HRESULT hr;
CDBID dbidOld(DBKIND_GUID_NAME, m_pIndexID->uName.pwszName);
CDBID dbidNew(DBKIND_NAME, L"abc123");
// At this time no providers support DBKIND_GUID_NAME
dbidOld.uGuid.guid = DBGUID_DSO;
TEST2C_(hr = AlterIndex(&dbidOld, &dbidNew, FALSE), DB_E_NOINDEX, S_OK)
if(DB_E_NOINDEX == hr)
odtLog<<L"INFO: Index IDs of DBKIND_GUID_NAME are considered invalid.\n";
CLEANUP:
Refresh_m_pIndexID(hr, dbidNew);
TRETURN
}
// }} TCW_VAR_PROTOTYPE_END
// {{ TCW_VAR_PROTOTYPE(32)
//*-----------------------------------------------------------------------
// @mfunc General - pIndexID is DBKIND_GUID_PROPID
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCAI_SingCol::Variation_32()
{
TBEGIN
HRESULT hr;
CDBID dbidOld(DBKIND_GUID_PROPID, NULL);
CDBID dbidNew(DBKIND_NAME, L"abc123");
// At this time no providers support DBKIND_GUID_PROPID
dbidOld.uName.ulPropid = 666;
dbidOld.uGuid.guid = DBGUID_DSO;
TEST2C_(hr = AlterIndex(&dbidOld, &dbidNew, FALSE), DB_E_NOINDEX, S_OK)
if(DB_E_NOINDEX == hr)
odtLog<<L"INFO: Index IDs of DBKIND_GUID_PROPID are considered invalid.\n";
CLEANUP:
Refresh_m_pIndexID(hr, dbidNew);
TRETURN
}
// }} TCW_VAR_PROTOTYPE_END
// {{ TCW_VAR_PROTOTYPE(33)
//*-----------------------------------------------------------------------
// @mfunc General - pIndexID is DBKIND_PGUID_NAME
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCAI_SingCol::Variation_33()
{
TBEGIN
HRESULT hr;
CDBID dbidOld(DBKIND_PGUID_NAME, m_pIndexID->uName.pwszName);
CDBID dbidNew(DBKIND_NAME, L"abc123");
GUID guid = DBGUID_ROW;
// At this time no providers support DBKIND_PGUID_NAME
dbidOld.uGuid.pguid = &guid;
TEST2C_(hr = AlterIndex(&dbidOld, &dbidNew, FALSE), DB_E_NOINDEX, S_OK)
if(DB_E_NOINDEX == hr)
odtLog<<L"INFO: Index IDs of DBKIND_PGUID_NAME are considered invalid.\n";
CLEANUP:
Refresh_m_pIndexID(hr, dbidNew);
TRETURN
}
// }} TCW_VAR_PROTOTYPE_END
// {{ TCW_VAR_PROTOTYPE(34)
//*-----------------------------------------------------------------------
// @mfunc General - pIndexID is DBKIND_PGUID_PROPID
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCAI_SingCol::Variation_34()
{
TBEGIN
HRESULT hr;
CDBID dbidOld(DBKIND_PGUID_PROPID, NULL);
CDBID dbidNew(DBKIND_NAME, L"abc123");
GUID guid = DBGUID_ROW;
// At this time no providers support DBKIND_PGUID_PROPID
dbidOld.uName.ulPropid = 666;
dbidOld.uGuid.pguid = &guid;
TEST2C_(hr = AlterIndex(&dbidOld, &dbidNew, FALSE), DB_E_NOINDEX, S_OK)
if(DB_E_NOINDEX == hr)
odtLog<<L"INFO: Index IDs of DBKIND_PGUID_PROPID are considered invalid.\n";
CLEANUP:
Refresh_m_pIndexID(hr, dbidNew);
TRETURN
}
// }} TCW_VAR_PROTOTYPE_END
// {{ TCW_VAR_PROTOTYPE(35)
//*-----------------------------------------------------------------------
// @mfunc General - pIndexID is DBKIND_PROPID
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCAI_SingCol::Variation_35()
{
TBEGIN
HRESULT hr;
CDBID dbidOld(DBKIND_PROPID, NULL);
CDBID dbidNew(DBKIND_NAME, L"abc123");
// At this time no providers support DBKIND_PROPID
dbidOld.uName.ulPropid = 666;
TEST2C_(hr = AlterIndex(&dbidOld, &dbidNew, FALSE), DB_E_NOINDEX, S_OK)
if(DB_E_NOINDEX == hr)
odtLog<<L"INFO: Index IDs of DBKIND_PROPID are considered invalid.\n";
CLEANUP:
Refresh_m_pIndexID(hr, dbidNew);
TRETURN
}
// }} TCW_VAR_PROTOTYPE_END
// {{ TCW_VAR_PROTOTYPE(36)
//*-----------------------------------------------------------------------
// @mfunc General - pIndexID is DBKIND_GUID
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCAI_SingCol::Variation_36()
{
TBEGIN
HRESULT hr;
CDBID dbidOld(DBKIND_GUID, NULL);
CDBID dbidNew(DBKIND_NAME, L"abc123");
// At this time no providers support DBKIND_GUID
dbidOld.uGuid.guid = DBGUID_DSO;
TEST2C_(hr = AlterIndex(&dbidOld, &dbidNew, FALSE), DB_E_NOINDEX, S_OK)
if(DB_E_NOINDEX == hr)
odtLog<<L"INFO: Index IDs of DBKIND_GUID are considered invalid.\n";
CLEANUP:
Refresh_m_pIndexID(hr, dbidNew);
TRETURN
}
// }} TCW_VAR_PROTOTYPE_END
// {{ TCW_VAR_PROTOTYPE(37)
//*-----------------------------------------------------------------------
// @mfunc General - AlterIndex with rowset open on different table
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCAI_SingCol::Variation_37()
{
TBEGIN
CDBID dbidNew(DBKIND_NAME, L"MtRainier");
DBID * pdbidTable = &(m_pNoNullTable->GetTableIDRef());
IRowset * pIRowset = NULL;
HRESULT hr = E_FAIL;
// Open a rowset on our other table
TESTC_(m_pIOpenRowset->OpenRowset(NULL, pdbidTable,
NULL, IID_IRowset, 0, NULL, (IUnknown**)
&pIRowset), S_OK);
TESTC_(hr = AlterIndex(m_pIndexID, &dbidNew), S_OK);
CLEANUP:
SAFE_RELEASE(pIRowset);
Refresh_m_pIndexID(hr, dbidNew);
TRETURN
}
// }} TCW_VAR_PROTOTYPE_END
// {{ TCW_TERMINATE_METHOD
//*-----------------------------------------------------------------------
// @mfunc TestCase Termination Routine
//
// @rdesc TEST_PASS or TEST_FAIL
//
BOOL TCAI_SingCol::Terminate()
{
// TO DO: Add your own code here
// {{ TCW_TERM_BASECLASS_CHECK2
return(CAlterIndex::Terminate());
} // }}
// }} TCW_TERMINATE_METHOD_END
// }} TCW_TC_PROTOTYPE_END
// {{ TCW_TC_PROTOTYPE(TCBoundary_SingCol)
//*-----------------------------------------------------------------------
//| Test Case: TCBoundary_SingCol - Boundary cases
//| Created: 8/2/1999
//*-----------------------------------------------------------------------
//*-----------------------------------------------------------------------
// @mfunc TestCase Initialization Routine
//
// @rdesc TRUE or FALSE
//
BOOL TCBoundary_SingCol::Init()
{
// {{ TCW_INIT_BASECLASS_CHECK
return CAlterIndex::Init();
// }}
}
// {{ TCW_VAR_PROTOTYPE(1)
//*-----------------------------------------------------------------------
// @mfunc E_INVALIDARG - pTableID = NULL
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCBoundary_SingCol::Variation_1()
{
TBEGIN
CDBID dbidNew(DBKIND_NAME, L"GoldFinger");
TESTC_(m_pIAlterIndex->AlterIndex(NULL, m_pIndexID, &dbidNew, 0, NULL), E_INVALIDARG)
CLEANUP:
TRETURN
}
// }} TCW_VAR_PROTOTYPE_END
// {{ TCW_VAR_PROTOTYPE(2)
//*-----------------------------------------------------------------------
// @mfunc E_INVALIDARG - pIndexID = NULL
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCBoundary_SingCol::Variation_2()
{
TBEGIN
CDBID dbidNew(DBKIND_NAME, L"GoldFinger2");
TESTC_(m_pIAlterIndex->AlterIndex(&(m_pTable->GetTableID()), NULL, &dbidNew, 0, NULL), E_INVALIDARG)
CLEANUP:
TRETURN
}
// }} TCW_VAR_PROTOTYPE_END
// {{ TCW_VAR_PROTOTYPE(3)
//*-----------------------------------------------------------------------
// @mfunc E_INVALIDARG - pTableID = NULL and pIndexID = NULL
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCBoundary_SingCol::Variation_3()
{
TBEGIN
CDBID dbidNew(DBKIND_NAME, L"GoldFinger3");
TESTC_(m_pIAlterIndex->AlterIndex(NULL, NULL, &dbidNew, 0, NULL), E_INVALIDARG)
CLEANUP:
TRETURN
}
// }} TCW_VAR_PROTOTYPE_END
// {{ TCW_VAR_PROTOTYPE(4)
//*-----------------------------------------------------------------------
// @mfunc E_INVALIDARG - cPropSets > 0 and rgPropSets NULL
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCBoundary_SingCol::Variation_4()
{
TBEGIN
CDBID dbidNew(DBKIND_NAME, L"DrEvil");
TESTC_(m_pIAlterIndex->AlterIndex(NULL, NULL, &dbidNew, 3, NULL), E_INVALIDARG)
CLEANUP:
TRETURN
}
// }} TCW_VAR_PROTOTYPE_END
// {{ TCW_VAR_PROTOTYPE(5)
//*-----------------------------------------------------------------------
// @mfunc E_INVALIDARG - cProperties != 0 and rgProperties NULL
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCBoundary_SingCol::Variation_5()
{
TBEGIN
CDBID dbidNew(DBKIND_NAME, L"MrBigglesworth");
DBPROPSET * prgPropSets=NULL;
ULONG cPropSets = 0;
SetProperty(DBPROP_INDEX_AUTOUPDATE, DBPROPSET_INDEX, &cPropSets, &prgPropSets, (void*)VARIANT_TRUE, DBTYPE_BOOL, DBPROPOPTIONS_REQUIRED);
SAFE_FREE(prgPropSets[0].rgProperties);
TESTC_(m_pIAlterIndex->AlterIndex(NULL, NULL, &dbidNew, cPropSets, prgPropSets), E_INVALIDARG)
CLEANUP:
FreeProperties(&cPropSets, &prgPropSets);
TRETURN
}
// }} TCW_VAR_PROTOTYPE_END
// {{ TCW_VAR_PROTOTYPE(6)
//*-----------------------------------------------------------------------
// @mfunc DB_E_NOTABLE - *pTableID == DB_NULLID
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCBoundary_SingCol::Variation_6()
{
TBEGIN
DBID dbTableID = DB_NULLID;
CDBID dbidNew(DBKIND_NAME, L"Cello");
TESTC_(AlterIndex(&dbTableID, m_pIndexID, &dbidNew, FALSE), DB_E_NOTABLE);
CLEANUP:
TRETURN
}
// }} TCW_VAR_PROTOTYPE_END
// {{ TCW_VAR_PROTOTYPE(7)
//*-----------------------------------------------------------------------
// @mfunc DB_E_NOTABLE - pTableID->uName is NULL
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCBoundary_SingCol::Variation_7()
{
TBEGIN
CDBID dbTableID(DBKIND_NAME, NULL);
CDBID dbidNew(DBKIND_NAME, L"Cello2");
TESTC_(AlterIndex(&dbTableID, m_pIndexID, &dbidNew, FALSE), DB_E_NOTABLE);
CLEANUP:
TRETURN
}
// }} TCW_VAR_PROTOTYPE_END
// {{ TCW_VAR_PROTOTYPE(8)
//*-----------------------------------------------------------------------
// @mfunc DB_E_NOTABLE - pTableID->uName is empty string
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCBoundary_SingCol::Variation_8()
{
TBEGIN
CDBID dbTableID(DBKIND_NAME, L"");
CDBID dbidNew(DBKIND_NAME, L"Trumpet");
TESTC_(AlterIndex(&dbTableID, m_pIndexID, &dbidNew, FALSE), DB_E_NOTABLE);
CLEANUP:
TRETURN
}
// }} TCW_VAR_PROTOTYPE_END
// {{ TCW_VAR_PROTOTYPE(9)
//*-----------------------------------------------------------------------
// @mfunc DB_E_NOTABLE - Table name invalid
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCBoundary_SingCol::Variation_9()
{
TBEGIN
CDBID dbidNew(DBKIND_NAME, L"Clarinet");
CDBID dbidTable(DBKIND_NAME, wcsDuplicate(m_pTable->GetTableID().uName.pwszName));
size_t iChar;
HRESULT hr = E_FAIL;
size_t cchInvalid = wcslen(m_pwszInvalidTableChars);
size_t cchName = wcslen(m_pTable->GetTableID().uName.pwszName);
WCHAR wszInvalidChar[2] = L"A";
// We must have at least one invalid character to test this
TESTC_PROVIDER(cchInvalid > 0);
// There must be at least two characters in the existing table
TESTC(cchName > 1);
// Replace the last character in the valid name with invalid ones
for (iChar = 0; iChar < cchInvalid; iChar++)
{
dbidTable.uName.pwszName[cchName-1] = m_pwszInvalidTableChars[iChar];
if (!CHECK(hr = AlterIndex(&dbidTable, m_pIndexID, &dbidNew, FALSE), DB_E_NOTABLE))
{
wszInvalidChar[0] = m_pwszInvalidTableChars[iChar];
odtLog << L"Invalid character # " << iChar << " '" << wszInvalidChar << L"' failed.\n\n";
}
Refresh_m_pIndexID(hr, dbidNew);
}
// Reset back to the valid name
wcscpy(dbidTable.uName.pwszName, m_pTable->GetTableID().uName.pwszName);
// Now try invalid starting characters
cchInvalid = wcslen(m_pwszInvalidTableStartingChars);
// Replace the first character in the valid name with invalid ones
for (iChar = 0; iChar < cchInvalid; iChar++)
{
dbidTable.uName.pwszName[0] = m_pwszInvalidTableStartingChars[iChar];
if (!CHECK(hr = AlterIndex(&dbidTable, m_pIndexID, &dbidNew, FALSE), DB_E_NOTABLE))
{
wszInvalidChar[0] = m_pwszInvalidTableStartingChars[iChar];
odtLog << L"Invalid starting character # " << iChar << " '" << wszInvalidChar << L"' failed.\n\n";
}
Refresh_m_pIndexID(hr, dbidNew);
}
CLEANUP:
SAFE_FREE(dbidTable.uName.pwszName);
TRETURN
}
// }} TCW_VAR_PROTOTYPE_END
// {{ TCW_VAR_PROTOTYPE(10)
//*-----------------------------------------------------------------------
// @mfunc DB_E_NOTABLE - Table name exceeds max length
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCBoundary_SingCol::Variation_10()
{
TBEGIN
CDBID dbTableID(DBKIND_NAME, BuildValidName(m_cMaxTableName+1, L"IAlterIndex"));
CDBID dbidNew(DBKIND_NAME, L"Bass");
// TODO: It would really be better here to create an actual table of max
// length, and then use that name plus one char to see if provider will
// truncate name and then use the valid table. But since this doesn't
// work for ini files it's kinda useless. We need to create a separate max
// name length table here if not using an ini file and create an index on it.
TESTC_(AlterIndex(&dbTableID, m_pIndexID, &dbidNew, FALSE), DB_E_NOTABLE);
CLEANUP:
ReleaseDBID(&dbTableID, FALSE);
TRETURN
}
// }} TCW_VAR_PROTOTYPE_END
// {{ TCW_VAR_PROTOTYPE(11)
//*-----------------------------------------------------------------------
// @mfunc DB_E_NOTABLE - Table does not exist
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCBoundary_SingCol::Variation_11()
{
TBEGIN
CDBID dbidNew(DBKIND_NAME, L"GoldFinger4");
CDBID dbidTable(DBKIND_NAME, L"BogusX1");
TESTC_(m_pIAlterIndex->AlterIndex(&dbidTable, m_pIndexID, &dbidNew, 0, NULL), DB_E_NOTABLE)
CLEANUP:
TRETURN
}
// }} TCW_VAR_PROTOTYPE_END
// {{ TCW_VAR_PROTOTYPE(12)
//*-----------------------------------------------------------------------
// @mfunc DB_E_NOINDEX - Index does not exist
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCBoundary_SingCol::Variation_12()
{
TBEGIN
CDBID dbidNew(DBKIND_NAME, L"GoldFinger5");
CDBID dbidOld(DBKIND_NAME, L"BogusX1");
TESTC_(AlterIndex(&dbidOld, &dbidNew, FALSE), DB_E_NOINDEX);
CLEANUP:
TRETURN
}
// }} TCW_VAR_PROTOTYPE_END
// {{ TCW_VAR_PROTOTYPE(13)
//*-----------------------------------------------------------------------
// @mfunc DB_E_NOINDEX - *pIndexID == DB_NULLID
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCBoundary_SingCol::Variation_13()
{
TBEGIN
CDBID dbidNew(DBKIND_NAME, L"BogusX1");
DBID dbidOld = DB_NULLID;
TESTC_(AlterIndex(&dbidOld, &dbidNew, FALSE), DB_E_NOINDEX);
CLEANUP:
TRETURN
}
// }} TCW_VAR_PROTOTYPE_END
// {{ TCW_VAR_PROTOTYPE(14)
//*-----------------------------------------------------------------------
// @mfunc DB_E_NOINDEX - pIndexID->uName is NULL
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCBoundary_SingCol::Variation_14()
{
TBEGIN
CDBID dbidNew(DBKIND_NAME, L"BogusX1");
CDBID dbidOld(DBKIND_NAME, NULL);
TESTC_(AlterIndex(&dbidOld, &dbidNew, FALSE), DB_E_NOINDEX);
CLEANUP:
TRETURN
}
// }} TCW_VAR_PROTOTYPE_END
// {{ TCW_VAR_PROTOTYPE(15)
//*-----------------------------------------------------------------------
// @mfunc DB_E_NOINDEX - pIndexID->uName is empty string
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCBoundary_SingCol::Variation_15()
{
TBEGIN
CDBID dbidNew(DBKIND_NAME, L"BogusX1");
CDBID dbidOld(DBKIND_NAME, L"");
TESTC_(AlterIndex(&dbidOld, &dbidNew, FALSE), DB_E_NOINDEX);
CLEANUP:
TRETURN
}
// }} TCW_VAR_PROTOTYPE_END
// {{ TCW_VAR_PROTOTYPE(16)
//*-----------------------------------------------------------------------
// @mfunc DB_E_NOINDEX - pIndexID name is invalid
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCBoundary_SingCol::Variation_16()
{
TBEGIN
CDBID dbidNew(DBKIND_NAME, L"Trombone");
CDBID dbidOld(DBKIND_NAME, wcsDuplicate(m_pIndexID->uName.pwszName));
size_t iChar;
HRESULT hr = E_FAIL;
size_t cchInvalid = wcslen(m_pwszInvalidIndexChars);
size_t cchName = wcslen(m_pIndexID->uName.pwszName);
WCHAR wszInvalidChar[2] = L"A";
// We must have at least one invalid character to test this
TESTC_PROVIDER(cchInvalid > 0);
// There must be at least two characters in the existing index
TESTC(cchName > 1);
// Replace the last character in the valid name with invalid ones
for (iChar = 0; iChar < cchInvalid; iChar++)
{
dbidOld.uName.pwszName[cchName-1] = m_pwszInvalidIndexChars[iChar];
if (!CHECK(hr = AlterIndex(&dbidOld, &dbidNew, FALSE), DB_E_NOINDEX))
{
wszInvalidChar[0] = m_pwszInvalidIndexChars[iChar];
odtLog << L"Invalid character # " << iChar << " '" << wszInvalidChar << L"' failed.\n\n";
}
Refresh_m_pIndexID(hr, dbidNew);
}
// Reset back to the valid name
wcscpy(dbidOld.uName.pwszName, m_pIndexID->uName.pwszName);
// Now try invalid starting characters
cchInvalid = wcslen(m_pwszInvalidIndexStartingChars);
// Replace the first character in the valid name with invalid ones
for (iChar = 0; iChar < cchInvalid; iChar++)
{
dbidOld.uName.pwszName[0] = m_pwszInvalidIndexStartingChars[iChar];
if (!CHECK(hr = AlterIndex(&dbidOld, &dbidNew, FALSE), DB_E_NOINDEX))
{
wszInvalidChar[0] = m_pwszInvalidIndexStartingChars[iChar];
odtLog << L"Invalid starting character # " << iChar << " '" << wszInvalidChar << L"' failed.\n\n";
}
Refresh_m_pIndexID(hr, dbidNew);
}
CLEANUP:
SAFE_FREE(dbidOld.uName.pwszName);
TRETURN
}
// }} TCW_VAR_PROTOTYPE_END
// {{ TCW_VAR_PROTOTYPE(17)
//*-----------------------------------------------------------------------
// @mfunc DB_E_NOINDEX - pIndexID name exceeds max name length
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCBoundary_SingCol::Variation_17()
{
TBEGIN
CDBID dbidOld(DBKIND_NAME, BuildValidName(m_cMaxIndexName+1, L"IAlterIndex"));
CDBID dbidNew(DBKIND_NAME, L"Bass");
// TODO: It would really be better here to create an actual index of max
// length to see if the provider will find the max length one instead.
TESTC_(AlterIndex(&dbidOld, &dbidNew, FALSE), DB_E_NOINDEX);
CLEANUP:
ReleaseDBID(&dbidOld, FALSE);
TRETURN
}
// }} TCW_VAR_PROTOTYPE_END
// {{ TCW_VAR_PROTOTYPE(18)
//*-----------------------------------------------------------------------
// @mfunc DB_E_DUPLICATEINDEXID - The new index already exists
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCBoundary_SingCol::Variation_18()
{
TBEGIN
DBID * pdbidExisting = NULL;
DBINDEXCOLUMNDESC rgIndexColumnDesc[1];
// Create another index on the table so we can ensure there is a duplicate
// index with a name that doesn't match the current index name.
memset(rgIndexColumnDesc, 0, sizeof(rgIndexColumnDesc));
TESTC_(CreateIndex(&(m_pTable->GetTableID()), NULL, 1,
rgIndexColumnDesc, 0, NULL, &pdbidExisting), S_OK);
TESTC_(AlterIndex(m_pIndexID, pdbidExisting), DB_E_DUPLICATEINDEXID);
CLEANUP:
// Drop the duplicate index
if (pdbidExisting)
CHECK(m_pIIndexDef->DropIndex(&(m_pTable->GetTableID()), pdbidExisting), S_OK);
ReleaseDBID(pdbidExisting);
TRETURN
}
// }} TCW_VAR_PROTOTYPE_END
// {{ TCW_VAR_PROTOTYPE(19)
//*-----------------------------------------------------------------------
// @mfunc DBSEC_E_PERMISSIONDENIED - Insufficient permissions to alter index
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCBoundary_SingCol::Variation_19()
{
TBEGIN
ULONG cExPropSets = 0;
DBPROPSET * prgExPropSets = NULL;
CDBID dbidNew(DBKIND_NAME, L"GoldRush");
IAlterIndex * pIAlterIndex = NULL;
IDBCreateSession * pIDBCreateSession = NULL;
CSessionObject SessionObject(L"TCBoundary_SingCol");
// Save the IAlterIndex object we use off our normal session
pIAlterIndex = m_pIAlterIndex;
m_pIAlterIndex = NULL;
// Create a new session with DBPROP_INIT_MODE DB_MODE_READ
// Set mode prop
TESTC(SetProperty(DBPROP_INIT_MODE, DBPROPSET_DBINIT, &cExPropSets, &prgExPropSets, (void*)DB_MODE_READ, DBTYPE_I4, DBPROPOPTIONS_REQUIRED));
// Create DSO
TESTC_(SessionObject.CreateDataSourceObject(), S_OK);
// Initialize the DSO with these props
TESTC_PROVIDER(S_OK == SessionObject.InitializeDSO(REINITIALIZE_YES, cExPropSets, prgExPropSets));
// Create the session object
TESTC(VerifyInterface(SessionObject.m_pIDBInitialize, IID_IDBCreateSession, DATASOURCE_INTERFACE, (IUnknown **)&pIDBCreateSession));
// Get the new IAlterIndex
TESTC_(pIDBCreateSession->CreateSession(NULL, IID_IAlterIndex, (IUnknown **)&m_pIAlterIndex), S_OK);
TESTC_(AlterIndex(m_pIndexID, &dbidNew), DB_SEC_E_PERMISSIONDENIED);
CLEANUP:
// Free the init props
FreeProperties(&cExPropSets, &prgExPropSets);
// Release the second session's IAlterIndex
SAFE_RELEASE(m_pIAlterIndex);
// Release the second session's pIDBCreateSession
SAFE_RELEASE(pIDBCreateSession);
// Put the AlterIndex interface back to normal
m_pIAlterIndex = pIAlterIndex;
// Release the r/o session object
SessionObject.ReleaseDBSession();
SessionObject.ReleaseDataSourceObject();
TRETURN
}
// }} TCW_VAR_PROTOTYPE_END
// {{ TCW_VAR_PROTOTYPE(20)
//*-----------------------------------------------------------------------
// @mfunc DB_E_BADINDEXID - pNewIndexID == DB_NULLID
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCBoundary_SingCol::Variation_20()
{
TBEGIN
DBID dbidNew = DB_NULLID;
TESTC_(AlterIndex(m_pIndexID, &dbidNew), DB_E_BADINDEXID);
CLEANUP:
TRETURN
}
// }} TCW_VAR_PROTOTYPE_END
// {{ TCW_VAR_PROTOTYPE(21)
//*-----------------------------------------------------------------------
// @mfunc DB_E_BADINDEXID - pNewIndexID->uName is NULL
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCBoundary_SingCol::Variation_21()
{
TBEGIN
CDBID dbidNew(DBKIND_NAME, NULL);
TESTC_(AlterIndex(m_pIndexID, &dbidNew), DB_E_BADINDEXID);
CLEANUP:
TRETURN
}
// }} TCW_VAR_PROTOTYPE_END
// {{ TCW_VAR_PROTOTYPE(22)
//*-----------------------------------------------------------------------
// @mfunc DB_E_BADINDEXID - pNewIndexID->uName is empty string
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCBoundary_SingCol::Variation_22()
{
TBEGIN
CDBID dbidNew(DBKIND_NAME, L"");
TESTC_(AlterIndex(m_pIndexID, &dbidNew), DB_E_BADINDEXID);
CLEANUP:
TRETURN
}
// }} TCW_VAR_PROTOTYPE_END
// {{ TCW_VAR_PROTOTYPE(23)
//*-----------------------------------------------------------------------
// @mfunc DB_E_BADINDEXID - Specify an invalid new index ID
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCBoundary_SingCol::Variation_23()
{
TBEGIN
CDBID dbidNew(DBKIND_NAME, wcsDuplicate(m_pIndexID->uName.pwszName));
size_t iChar;
HRESULT hr = E_FAIL;
size_t cchInvalid = wcslen(m_pwszInvalidIndexChars);
size_t cchName = wcslen(m_pIndexID->uName.pwszName);
WCHAR wszInvalidChar[2] = L"A";
// We must have at least one invalid character to test this
TESTC_PROVIDER(cchInvalid > 0);
// There must be at least two characters in the existing index
TESTC(cchName > 1);
// Replace the last character in the valid name with invalid ones
for (iChar = 0; iChar < cchInvalid; iChar++)
{
dbidNew.uName.pwszName[cchName-1] = m_pwszInvalidIndexChars[iChar];
if (!CHECK(hr = AlterIndex(m_pIndexID, &dbidNew), DB_E_BADINDEXID))
{
wszInvalidChar[0] = m_pwszInvalidIndexChars[iChar];
odtLog << L"Invalid character # " << iChar << " '" << wszInvalidChar << L"' failed.\n\n";
}
Refresh_m_pIndexID(hr, dbidNew);
}
// Reset back to the valid name
wcscpy(dbidNew.uName.pwszName, m_pIndexID->uName.pwszName);
// Now try invalid starting characters
cchInvalid = wcslen(m_pwszInvalidIndexStartingChars);
// Replace the first character in the valid name with invalid ones
for (iChar = 0; iChar < cchInvalid; iChar++)
{
dbidNew.uName.pwszName[0] = m_pwszInvalidIndexStartingChars[iChar];
if (!CHECK(hr = AlterIndex(m_pIndexID, &dbidNew), DB_E_BADINDEXID))
{
wszInvalidChar[0] = m_pwszInvalidIndexStartingChars[iChar];
odtLog << L"Invalid starting character # " << iChar << " '" << wszInvalidChar << L"' failed.\n\n";
}
Refresh_m_pIndexID(hr, dbidNew);
}
CLEANUP:
SAFE_FREE(dbidNew.uName.pwszName);
TRETURN
}
// }} TCW_VAR_PROTOTYPE_END
// {{ TCW_VAR_PROTOTYPE(24)
//*-----------------------------------------------------------------------
// @mfunc DB_E_BADINDEXID - pNewIndexID name exceeds max name length
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCBoundary_SingCol::Variation_24()
{
TBEGIN
CDBID dbidNew(DBKIND_NAME, BuildValidName(m_cMaxIndexName+1, L"IAlterIndex"));
TESTC_(AlterIndex(m_pIndexID, &dbidNew), DB_E_BADINDEXID);
CLEANUP:
ReleaseDBID(&dbidNew, FALSE);
TRETURN
}
// }} TCW_VAR_PROTOTYPE_END
// {{ TCW_VAR_PROTOTYPE(25)
//*-----------------------------------------------------------------------
// @mfunc DB_E_INDEXINUSE - AlterIndex with index in use
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCBoundary_SingCol::Variation_25()
{
TBEGIN
CDBID dbidNew(DBKIND_NAME, L"OddJobHat");
DBID * pdbidTable = &(m_pTable->GetTableIDRef());
IRowsetIndex * pIRowsetIndex = NULL;
// If neither integrated nor separate indexes are supported we
// don't have a way to ensure the index is in use.
TESTC_PROVIDER(m_ulIRowsetIndex != OIS_NONE);
// If integrated indexes are supported we can pass the table id
// otherwise table ID must be NULL;
if (m_ulIRowsetIndex & OIS_ROWSET)
pdbidTable = NULL;
// Open a rowset using this index
TESTC_(m_pIOpenRowset->OpenRowset(NULL, pdbidTable,
m_pIndexID, IID_IRowsetIndex, 0, NULL, (IUnknown**)
&pIRowsetIndex), S_OK);
if (m_ulIRowsetIndex & OIS_ROWSET)
{
TESTC_(AlterIndex(m_pIndexID, &dbidNew), DB_E_INDEXINUSE);
}
else
{
TEST2C_(AlterIndex(m_pIndexID, &dbidNew), DB_E_INDEXINUSE, DB_E_TABLEINUSE);
}
CLEANUP:
SAFE_RELEASE(pIRowsetIndex);
TRETURN
}
// }} TCW_VAR_PROTOTYPE_END
// {{ TCW_VAR_PROTOTYPE(26)
//*-----------------------------------------------------------------------
// @mfunc DB_E_TABLEINUSE - AlterIndex with table in use
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCBoundary_SingCol::Variation_26()
{
TBEGIN
CDBID dbidNew(DBKIND_NAME, L"OddJobHat");
DBID * pdbidTable = &(m_pTable->GetTableIDRef());
IRowset * pIRowset = NULL;
HRESULT hr = E_FAIL;
// Open a rowset using this index
TESTC_(m_pIOpenRowset->OpenRowset(NULL, pdbidTable,
NULL, IID_IRowset, 0, NULL, (IUnknown**)
&pIRowset), S_OK);
// Some providers may allow indexes to be altered while the table is open
TEST2C_(hr = AlterIndex(m_pIndexID, &dbidNew), S_OK, DB_E_TABLEINUSE);
CLEANUP:
Refresh_m_pIndexID(hr, dbidNew);
SAFE_RELEASE(pIRowset);
TRETURN
}
// }} TCW_VAR_PROTOTYPE_END
// {{ TCW_VAR_PROTOTYPE(27)
//*-----------------------------------------------------------------------
// @mfunc S_OK - cPropSets == 0, rgPropSets is ignored
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCBoundary_SingCol::Variation_27()
{
TBEGIN
HRESULT hr;
CDBID dbidNew(DBKIND_NAME, L"Oboe");
m_cPropSets = 0;
m_rgPropSets = INVALID(DBPROPSET *);
TESTC_(hr = AlterIndex(m_pIndexID, &dbidNew), S_OK)
CLEANUP:
Refresh_m_pIndexID(hr, dbidNew);
m_rgPropSets = NULL;
TRETURN
}
// }} TCW_VAR_PROTOTYPE_END
// {{ TCW_VAR_PROTOTYPE(28)
//*-----------------------------------------------------------------------
// @mfunc DB_E_NOINDEX - AlterIndex on a dropped index
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCBoundary_SingCol::Variation_28()
{
TBEGIN
DBID * pdbidDropped = NULL;
CDBID dbidNew(DBKIND_NAME, L"Baritone");
DBINDEXCOLUMNDESC rgIndexColumnDesc[1];
// Create another index on the table so we can have one to drop safely
memset(rgIndexColumnDesc, 0, sizeof(rgIndexColumnDesc));
TESTC_(CreateIndex(&(m_pTable->GetTableID()), NULL, 1,
rgIndexColumnDesc, 0, NULL, &pdbidDropped), S_OK);
// Drop the duplicate index
if (pdbidDropped)
CHECK(m_pIIndexDef->DropIndex(&(m_pTable->GetTableID()), pdbidDropped), S_OK);
TESTC_(AlterIndex(pdbidDropped, &dbidNew, FALSE), DB_E_NOINDEX);
CLEANUP:
ReleaseDBID(pdbidDropped);
TRETURN
}
// }} TCW_VAR_PROTOTYPE_END
// {{ TCW_VAR_PROTOTYPE(29)
//*-----------------------------------------------------------------------
// @mfunc DB_E_NOTABLE - Pass procedure name as existing table name
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCBoundary_SingCol::Variation_29()
{
TBEGIN
CDBID dbidNew(DBKIND_NAME, L"Cello");
LPWSTR pwszProcName = MakeObjectName(L"IAlterIn", m_cMaxTableName);
// Create a stored proc with a different name than the table
TESTC_PROVIDER(S_OK == m_pTable->ExecuteCommand(CREATE_PROC, IID_NULL,
pwszProcName,NULL,NULL, NULL, EXECUTE_IFNOERROR, 0, NULL,
NULL, NULL, NULL));
{
CDBID dbTableID(DBKIND_NAME, pwszProcName);
TESTC_(AlterIndex(&dbTableID, m_pIndexID, &dbidNew, FALSE), DB_E_NOTABLE);
}
CLEANUP:
// Drop the stored proc we created above. Note it might not exist.
m_pTable->ExecuteCommand(DROP_PROC, IID_NULL,
pwszProcName,NULL,NULL, NULL, EXECUTE_IFNOERROR, 0, NULL,
NULL, NULL, NULL);
SAFE_FREE(pwszProcName);
TRETURN
}
// }} TCW_VAR_PROTOTYPE_END
// {{ TCW_VAR_PROTOTYPE(30)
//*-----------------------------------------------------------------------
// @mfunc DB_E_NOINDEX - Pass procedure name as existing index name
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCBoundary_SingCol::Variation_30()
{
TBEGIN
CDBID dbidNew(DBKIND_NAME, L"Cello");
LPWSTR pwszProcName = MakeObjectName(L"IAlterIn", m_cMaxTableName);
// Create a stored proc with a different name than the table
TESTC_PROVIDER(S_OK == m_pTable->ExecuteCommand(CREATE_PROC, IID_NULL,
pwszProcName,NULL,NULL, NULL, EXECUTE_IFNOERROR, 0, NULL,
NULL, NULL, NULL));
{
CDBID dbIndexID(DBKIND_NAME, pwszProcName);
TESTC_(AlterIndex(&dbIndexID, &dbidNew, FALSE), DB_E_NOINDEX);
}
CLEANUP:
// Drop the stored proc we created above. Note it might not exist.
m_pTable->ExecuteCommand(DROP_PROC, IID_NULL,
pwszProcName,NULL,NULL, NULL, EXECUTE_IFNOERROR, 0, NULL,
NULL, NULL, NULL);
SAFE_FREE(pwszProcName);
TRETURN
}
// }} TCW_VAR_PROTOTYPE_END
// {{ TCW_VAR_PROTOTYPE(31)
//*-----------------------------------------------------------------------
// @mfunc DB_E_NOINDEX - Pass valid index from different table as existing index name
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCBoundary_SingCol::Variation_31()
{
TBEGIN
CDBID dbidNew(DBKIND_NAME, L"Cello");
DBID * pIndexID = NULL;
// Create an index on a different table
TESTC_(CreateIndex(&(m_pNoNullTable->GetTableID()),
NULL, m_cIndexColumnDesc,m_pIndexColumnDesc, 0, NULL,
&pIndexID), S_OK);
TESTC_(AlterIndex(pIndexID, &dbidNew, FALSE), DB_E_NOINDEX);
CLEANUP:
// Drop the index on the other table
TESTC_(m_pIIndexDef->DropIndex(&(m_pNoNullTable->GetTableID()), pIndexID), S_OK);
TRETURN
}
// }} TCW_VAR_PROTOTYPE_END
// {{ TCW_VAR_PROTOTYPE(32)
//*-----------------------------------------------------------------------
// @mfunc DB_E_ERRORSOCCURRED - Alter second index on table to be duplicate primary key
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCBoundary_SingCol::Variation_32()
{
TBEGIN
HRESULT hr;
CDBID dbidNew(DBKIND_NAME, BuildValidName(m_cMaxIndexName, L"XYZ"));
DBID * pTableID = &(m_pNoNullTable->GetTableIDRef());
DBCOLUMNDESC * pColumnDesc = NULL;
DBPROPSET * pColPropSets = NULL;
ULONG cColPropSets = 0;
DBORDINAL cCols = m_pTable->CountColumnsOnTable();
ULONG iCol;
DBINDEXCOLUMNDESC *pIndexColumnDesc = NULL;
DBID * pIndexID = NULL;
CTable NewTable(m_pThisTestModule->m_pIUnknown2, (LPWSTR)gwszModuleName, NONULLS);
// Note we could just AlterTable on the current automaketable to create a
// PrimaryKey constraint, but at the time this was written AlterTable did not
// properly support this.
// Initialize pIndexColumnDesc
SAFE_ALLOC(pIndexColumnDesc, DBINDEXCOLUMNDESC, cCols);
memset(pIndexColumnDesc, 0, (size_t)(sizeof(DBINDEXCOLUMNDESC)*cCols));
// Get the DBCOLUMNDESC information from the automaketable
TESTC_(m_pTable->BuildColumnDescs(&pColumnDesc), S_OK);
// Create a primary key index on the automaketable so we can tell which column
// will support a primary key.
TESTC(m_cPropSets == 0);
SetSettableProperty(DBPROP_INDEX_PRIMARYKEY, DBPROPSET_INDEX, &m_cPropSets, &m_rgPropSets, (void*)VARIANT_TRUE, DBTYPE_BOOL, DBPROPOPTIONS_REQUIRED);
// Create the index to be altered
TESTC_PROVIDER(S_OK == CreateAlterableIndex(pTableID, NULL, m_cIndexColumnDesc,
pIndexColumnDesc, m_cPropSets, m_rgPropSets, &pIndexID));
// Drop the index on the automaketable - we only wanted the column descs
TESTC_(m_pIIndexDef->DropIndex(pTableID, pIndexID), S_OK);
// Add a PrimaryKey prop for this column for the new table
for (iCol = 0; iCol < cCols; iCol++)
{
if (CompareDBID(*pIndexColumnDesc[iCol].pColumnID, pColumnDesc[iCol].dbcid))
{
SetProperty(DBPROP_COL_PRIMARYKEY, DBPROPSET_COLUMN,
&pColumnDesc[iCol].cPropertySets, &pColumnDesc[iCol].rgPropertySets,
(void*)VARIANT_TRUE, DBTYPE_BOOL, DBPROPOPTIONS_REQUIRED);
break;
}
}
TESTC(iCol < cCols);
// Set the column desc info for the new table
TESTC(NewTable.SetColumnDesc(pColumnDesc, cCols) != NULL);
NewTable.SetBuildColumnDesc(FALSE);
// Create the new table
TESTC_(NewTable.CreateTable(MIN_TABLE_ROWS, 0), S_OK);
// Create an index on the new table, using the same column as above.
TESTC_PROVIDER(S_OK == CreateIndex(&(NewTable.GetTableID()),
NULL, m_cIndexColumnDesc,pIndexColumnDesc, 0, NULL,
&pIndexID));
// Call AlterIndex to set this property.
// Since this is a duplicate PK it should fail.
TESTC_(hr = AlterIndex(&(NewTable.GetTableID()), pIndexID, &dbidNew), DB_E_ERRORSOCCURRED)
CLEANUP:
FreeProperties(&m_cPropSets, &m_rgPropSets);
SAFE_FREE(dbidNew.uName.pwszName);
SAFE_FREE(pIndexColumnDesc);
TRETURN
}
// }} TCW_VAR_PROTOTYPE_END
// {{ TCW_VAR_PROTOTYPE(33)
//*-----------------------------------------------------------------------
// @mfunc DB_S_ERRORSOCCURRED - Alter second index on table to be duplicate primary key
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCBoundary_SingCol::Variation_33()
{
TBEGIN
HRESULT hr;
CDBID dbidNew(DBKIND_NAME, BuildValidName(m_cMaxIndexName, L"XYZ"));
DBID * pTableID = &(m_pNoNullTable->GetTableIDRef());
DBCOLUMNDESC * pColumnDesc = NULL;
DBPROPSET * pColPropSets = NULL;
ULONG cColPropSets = 0;
DBORDINAL cCols = m_pTable->CountColumnsOnTable();
ULONG iCol;
DBINDEXCOLUMNDESC *pIndexColumnDesc = NULL;
DBID * pIndexID = NULL;
CTable NewTable(m_pThisTestModule->m_pIUnknown2, (LPWSTR)gwszModuleName, NONULLS);
// Note we could just AlterTable on the current automaketable to create a
// PrimaryKey constraint, but at the time this was written AlterTable did not
// properly support this.
// Initialize pIndexColumnDesc
SAFE_ALLOC(pIndexColumnDesc, DBINDEXCOLUMNDESC, cCols);
memset(pIndexColumnDesc, 0, (size_t)(sizeof(DBINDEXCOLUMNDESC)*cCols));
// Get the DBCOLUMNDESC information from the automaketable
TESTC_(m_pTable->BuildColumnDescs(&pColumnDesc), S_OK);
// Create a primary key index on the automaketable so we can tell which column
// will support a primary key.
TESTC(m_cPropSets == 0);
SetSettableProperty(DBPROP_INDEX_PRIMARYKEY, DBPROPSET_INDEX, &m_cPropSets, &m_rgPropSets, (void*)VARIANT_TRUE, DBTYPE_BOOL, DBPROPOPTIONS_REQUIRED);
// Create the index to be altered
TESTC_PROVIDER(S_OK == CreateAlterableIndex(pTableID, NULL, m_cIndexColumnDesc,
pIndexColumnDesc, m_cPropSets, m_rgPropSets, &pIndexID));
// Drop the index on the automaketable - we only wanted the column descs
TESTC_(m_pIIndexDef->DropIndex(pTableID, pIndexID), S_OK);
// Add a PrimaryKey prop for this column for the new table
for (iCol = 0; iCol < cCols; iCol++)
{
if (CompareDBID(*pIndexColumnDesc[iCol].pColumnID, pColumnDesc[iCol].dbcid))
{
SetProperty(DBPROP_COL_PRIMARYKEY, DBPROPSET_COLUMN,
&pColumnDesc[iCol].cPropertySets, &pColumnDesc[iCol].rgPropertySets,
(void*)VARIANT_TRUE, DBTYPE_BOOL, DBPROPOPTIONS_REQUIRED);
break;
}
}
TESTC(iCol < cCols);
// Set the column desc info for the new table
TESTC(NewTable.SetColumnDesc(pColumnDesc, cCols) != NULL);
NewTable.SetBuildColumnDesc(FALSE);
// Create the new table
TESTC_(NewTable.CreateTable(MIN_TABLE_ROWS, 0), S_OK);
// Reset the prop to optional
m_rgPropSets[0].rgProperties[0].dwOptions = DBPROPOPTIONS_OPTIONAL;
// Create an index on the new table, using the same column as above.
TESTC_PROVIDER(S_OK == CreateIndex(&(NewTable.GetTableID()),
NULL, m_cIndexColumnDesc,pIndexColumnDesc, 0, NULL,
&pIndexID));
// Call AlterIndex to set this property.
// Since this is a duplicate PK it should fail.
TESTC_(hr = AlterIndex(&(NewTable.GetTableID()), pIndexID, &dbidNew), DB_S_ERRORSOCCURRED)
CLEANUP:
FreeProperties(&m_cPropSets, &m_rgPropSets);
SAFE_FREE(dbidNew.uName.pwszName);
SAFE_FREE(pIndexColumnDesc);
TRETURN
}
// }} TCW_VAR_PROTOTYPE_END
// {{ TCW_TERMINATE_METHOD
//*-----------------------------------------------------------------------
// @mfunc TestCase Termination Routine
//
// @rdesc TEST_PASS or TEST_FAIL
//
BOOL TCBoundary_SingCol::Terminate()
{
// TO DO: Add your own code here
// {{ TCW_TERM_BASECLASS_CHECK2
return(CAlterIndex::Terminate());
} // }}
// }} TCW_TERMINATE_METHOD_END
// }} TCW_TC_PROTOTYPE_END
// {{ TCW_TC_PROTOTYPE(TCProp_SingCol)
//*-----------------------------------------------------------------------
//| Test Case: TCProp_SingCol - Property related tests
//| Created: 8/25/99
//*-----------------------------------------------------------------------
//*-----------------------------------------------------------------------
// @mfunc TestCase Initialization Routine
//
// @rdesc TRUE or FALSE
//
BOOL TCProp_SingCol::Init()
{
// {{ TCW_INIT_BASECLASS_CHECK
if(CAlterIndex::Init())
// }}
{
// TO DO: Add your own code here
return TRUE;
}
return FALSE;
}
// {{ TCW_VAR_PROTOTYPE(1)
//*-----------------------------------------------------------------------
// @mfunc DBPROP_INDEX_AUTOUPDATE
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCProp_SingCol::Variation_1()
{
TBEGIN
HRESULT hr;
CIndexInfo IndexInfo;
VARIANT_BOOL vbAutoUpdate = 100;
ULONG iVal;
// Get information about this index.
TESTC(IndexInfo.Init(m_pIOpenRowset, &(m_pTable->GetTableID()), m_pIndexID));
// Read current autoupdate value for first column of index (0 based).
vbAutoUpdate = *(VARIANT_BOOL *)IndexInfo.GetIndexValuePtr(0, IS_AUTO_UPDATE);
for (iVal = 0; iVal < NUMELEM(VariantBoolVals); iVal++)
{
//Set prop.
SetProperty(DBPROP_INDEX_AUTOUPDATE, DBPROPSET_INDEX, &m_cPropSets, &m_rgPropSets, (void*)VariantBoolVals[iVal], DBTYPE_BOOL, DBPROPOPTIONS_REQUIRED);
// If this val matches the initial value it should always succeed
if (VariantBoolVals[iVal] == vbAutoUpdate)
{
// Try to alter with this prop
TESTC_(hr = AlterIndex(m_pIndexID, NULL), S_OK)
}
else
{
// Try to alter with this prop
TEST2C_(hr = AlterIndex(m_pIndexID, NULL), S_OK, DB_E_ERRORSOCCURRED)
}
// Verify the prop status based on settability, etc.
TESTC(VerifyPropStatus(m_cPropSets, m_rgPropSets, DBPROP_INDEX_AUTOUPDATE, DBPROPSET_INDEX, DBPROPSTATUS_OK))
// If prop is VARIANT_TRUE, verify the index is auto-updatable
// VerifyAutoUpdate(hr, m_pTableID, m_pIndexID);
FreeProperties(&m_cPropSets, &m_rgPropSets);
}
CLEANUP:
FreeProperties(&m_cPropSets, &m_rgPropSets);
TRETURN
}
// }} TCW_VAR_PROTOTYPE_END
// {{ TCW_VAR_PROTOTYPE(2)
//*-----------------------------------------------------------------------
// @mfunc DBPROP_INDEX_CLUSTERED
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCProp_SingCol::Variation_2()
{
TBEGIN
HRESULT hr;
CIndexInfo IndexInfo;
VARIANT_BOOL vbClustered = 100;
ULONG iVal;
// Get information about this index.
TESTC(IndexInfo.Init(m_pIOpenRowset, &(m_pTable->GetTableID()), m_pIndexID));
// Read current autoupdate value for first column of index (0 based).
vbClustered = *(VARIANT_BOOL *)IndexInfo.GetIndexValuePtr(0, IS_CLUSTERED);
for (iVal = 0; iVal < NUMELEM(VariantBoolVals); iVal++)
{
//Set prop.
SetProperty(DBPROP_INDEX_CLUSTERED, DBPROPSET_INDEX, &m_cPropSets, &m_rgPropSets, (void*)VariantBoolVals[iVal], DBTYPE_BOOL, DBPROPOPTIONS_REQUIRED);
// If this val matches the initial value it should always succeed
if (VariantBoolVals[iVal] == vbClustered)
{
// Try to alter with this prop
TESTC_(hr = AlterIndex(m_pIndexID, NULL), S_OK)
}
else
{
// Try to alter with this prop
TEST2C_(hr = AlterIndex(m_pIndexID, NULL), S_OK, DB_E_ERRORSOCCURRED)
}
// Verify the prop status based on settability, etc.
TESTC(VerifyPropStatus(m_cPropSets, m_rgPropSets, DBPROP_INDEX_CLUSTERED, DBPROPSET_INDEX, DBPROPSTATUS_OK))
// Verify the index is clustered. Since verification is very provider-specific we
// won't attempt at this time.
// VerifyClustered(hr, m_pTableID, m_pIndexID);
FreeProperties(&m_cPropSets, &m_rgPropSets);
}
CLEANUP:
FreeProperties(&m_cPropSets, &m_rgPropSets);
TRETURN
}
// }} TCW_VAR_PROTOTYPE_END
// {{ TCW_VAR_PROTOTYPE(3)
//*-----------------------------------------------------------------------
// @mfunc DBPROP_INDEX_NULLS
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCProp_SingCol::Variation_3()
{
TBEGIN
HRESULT hr, hrCreateIndex = S_OK;
ULONG iVal, iCreateVal;
ULONG ulCurrentValue = DBPROPVAL_IN_ALLOWNULL;
ULONG cPropSets = 0;
DBPROPSET * pPropSets = NULL;
DBPROPSTATUS stExpected = DBPROPSTATUS_OK;
DBID * pTableID = &(m_pTable->GetTableIDRef());
CIndexInfo IndexInfo;
DBINDEXCOLUMNDESC *pIndexColumnDesc = NULL;
// Initialize pIndexColumnDesc
SAFE_ALLOC(pIndexColumnDesc, DBINDEXCOLUMNDESC, m_cIndexColumnDesc);
memset(pIndexColumnDesc, 0, (size_t)(sizeof(DBINDEXCOLUMNDESC)*m_cIndexColumnDesc));
// Because of Jolt behavior wrt setting only to default value with
// AlterIndex we need to loop through all values of the property and attempt
// to create an index with that property value first.
for (iCreateVal = 0; iCreateVal < NUMELEM(IndexNullVals); iCreateVal++)
{
// Set the property values for index creation
SetProperty(DBPROP_INDEX_NULLS, DBPROPSET_INDEX, &cPropSets, &pPropSets, (void *)(ULONG_PTR)IndexNullVals[iCreateVal].ulPropVal, DBTYPE_I4, DBPROPOPTIONS_REQUIRED);
// Create an index with this property set to the proper value. We assume
// failure to support the property value is valid and tested in IIndexDef
// test, so just allow failure.
hrCreateIndex = CreateIndex(pTableID, NULL, m_cIndexColumnDesc,
pIndexColumnDesc, cPropSets, pPropSets, &m_pIndexID);
while(hrCreateIndex == S_OK)
{
// Get information about this index.
TESTC(IndexInfo.Init(m_pIOpenRowset, pTableID, m_pIndexID));
// Read current INDEX_NULLS value for first column of index (0 based).
ulCurrentValue = *(ULONG *)IndexInfo.GetIndexValuePtr(0, IS_NULLS);
// If index creation succeeded we'd better have the value we asked for
TESTC(ulCurrentValue == IndexNullVals[iCreateVal].ulPropVal);
for (iVal = 0; iVal < NUMELEM(IndexNullVals); iVal++)
{
// For some providers AlterIndex can only set a property to it's current value
// so set expected prop status appropriately
if (ulCurrentValue != IndexNullVals[iVal].ulPropVal && m_fSetOnlyDefault)
stExpected = DBPROPSTATUS_NOTSETTABLE;
else
stExpected = DBPROPSTATUS_OK;
//Set prop as required.
SetProperty(DBPROP_INDEX_NULLS, DBPROPSET_INDEX, &m_cPropSets, &m_rgPropSets, (void*)(ULONG_PTR)IndexNullVals[iVal].ulPropVal, DBTYPE_I4, DBPROPOPTIONS_REQUIRED);
// Try to alter with this prop
hr = AlterIndex(m_pIndexID, NULL);
// Allow DB_E_ERRORSOCCURRED or S_OK
if (hr != DB_E_ERRORSOCCURRED)
CHECK(hr, S_OK);
// Verify the prop status based on settability, etc.
COMPARE(VerifyPropStatus(m_cPropSets, m_rgPropSets, DBPROP_INDEX_NULLS, DBPROPSET_INDEX, stExpected), TRUE);
// Verify the index null handling
VerifyNulls(hr,
m_pTable,
m_pIndexID,
IndexNullVals[iVal].ulPropVal,
m_cIndexColumnDesc,
pIndexColumnDesc
);
FreeProperties(&m_cPropSets, &m_rgPropSets);
} // Next alteration value
// Drop the index we created
CHECK(m_pIIndexDef->DropIndex(pTableID, m_pIndexID), S_OK);
// Create the next possible index
hrCreateIndex = CreateIndex(pTableID, NULL, m_cIndexColumnDesc,
pIndexColumnDesc, cPropSets, pPropSets, &m_pIndexID, TRUE);
} // Next supported index column set
// Make sure we got a valid error return from CreateIndex
// If the provider doesn't support property -> DB_E_ERRORSOCCURRED
// If other error occurs (duplicate column in index) -> E_FAIL
// The IIndexDef test should be checking for these.
if (hrCreateIndex != DB_E_ERRORSOCCURRED)
CHECK(hrCreateIndex, E_FAIL);
// Reset hrCreateIndex for next prop val
hrCreateIndex = S_OK;
// Free the previous prop values
FreeProperties(&cPropSets, &pPropSets);
// Reset the index col DBIDs. These are pointers to the CCol DBID
// so we don't want to release them.
memset(pIndexColumnDesc, 0, (size_t)(sizeof(DBINDEXCOLUMNDESC)*m_cIndexColumnDesc));
} // Next index creation value
CLEANUP:
SAFE_FREE(pIndexColumnDesc);
FreeProperties(&m_cPropSets, &m_rgPropSets);
TRETURN
}
// }} TCW_VAR_PROTOTYPE_END
// {{ TCW_VAR_PROTOTYPE(4)
//*-----------------------------------------------------------------------
// @mfunc DBPROP_INDEX_PRIMARYKEY
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCProp_SingCol::Variation_4()
{
TBEGIN
HRESULT hr, hrCreateIndex = S_OK;
ULONG iVal, iCreateVal;
ULONG cIndexes = 0;
VARIANT_BOOL vbCurrentValue = VARIANT_FALSE;
ULONG cPropSets = 0;
DBPROPSET * pPropSets = NULL;
DBPROPSTATUS stExpected = DBPROPSTATUS_OK;
DBID * pTableID = &(m_pNoNullTable->GetTableIDRef());
DBID IndexID = DB_NULLID;
DBID * pIndexID = &IndexID;
CIndexInfo IndexInfo;
DBINDEXCOLUMNDESC *pIndexColumnDesc = NULL;
// Initialize pIndexColumnDesc
SAFE_ALLOC(pIndexColumnDesc, DBINDEXCOLUMNDESC, m_cIndexColumnDesc);
memset(pIndexColumnDesc, 0, (size_t)(sizeof(DBINDEXCOLUMNDESC)*m_cIndexColumnDesc));
// Because of provider behavior wrt setting only to default value with
// AlterIndex we need to loop through all values of the property and attempt
// to create an index with that property value first.
for (iCreateVal = 0; iCreateVal < NUMELEM(VariantBoolVals); iCreateVal++)
{
// Set the property values for index creation
SetProperty(DBPROP_INDEX_PRIMARYKEY, DBPROPSET_INDEX, &cPropSets, &pPropSets, (void*)VariantBoolVals[iCreateVal], DBTYPE_BOOL, DBPROPOPTIONS_REQUIRED);
// Create an index with this property set to the proper value. We assume
// failure to support the property value is valid and tested in IIndexDef
// test, so just allow failure.
hrCreateIndex = CreateIndex(pTableID, NULL, m_cIndexColumnDesc,
pIndexColumnDesc, cPropSets, pPropSets, &pIndexID);
cIndexes = 0;
while(hrCreateIndex == S_OK)
{
cIndexes++;
// Get information about this index.
TESTC(IndexInfo.Init(m_pIOpenRowset, pTableID, pIndexID));
// Read current UNIQUE value for first column of index (0 based).
vbCurrentValue = *(VARIANT_BOOL *)IndexInfo.GetIndexValuePtr(0, IS_PRIMARY_KEY);
// If index creation succeeded we'd better have the value we asked for
TESTC(vbCurrentValue == VariantBoolVals[iCreateVal]);
for (iVal = 0; iVal < NUMELEM(VariantBoolVals); iVal++)
{
// For some providers AlterIndex can only set a property to it's current value
// so set expected prop status appropriately
if (vbCurrentValue != VariantBoolVals[iVal] && m_fSetOnlyDefault)
stExpected = DBPROPSTATUS_NOTSETTABLE;
else
stExpected = DBPROPSTATUS_OK;
//Set prop as required.
SetProperty(DBPROP_INDEX_PRIMARYKEY, DBPROPSET_INDEX, &m_cPropSets, &m_rgPropSets, (void*)VariantBoolVals[iVal], DBTYPE_BOOL, DBPROPOPTIONS_REQUIRED);
// Try to alter with this prop
hr = AlterIndex(pTableID, pIndexID, (DBID *)NULL);
// Allow DB_E_ERRORSOCCURRED or S_OK
if (hr != DB_E_ERRORSOCCURRED)
CHECK(hr, S_OK);
// Verify the prop status based on settability, etc.
COMPARE(VerifyPropStatus(m_cPropSets, m_rgPropSets, DBPROP_INDEX_PRIMARYKEY, DBPROPSET_INDEX, stExpected), TRUE);
// Verify the primary key
VerifyPrimaryKey(hr,
m_pNoNullTable,
pIndexID,
VariantBoolVals[iVal],
m_cIndexColumnDesc,
pIndexColumnDesc
);
FreeProperties(&m_cPropSets, &m_rgPropSets);
} // Next alteration value
// Drop the index we created
CHECK(m_pIIndexDef->DropIndex(pTableID, pIndexID), S_OK);
// Only test the maximum index count to speed up testing when using multipart
// keys
if (cIndexes >= MAX_INDEX_COUNT)
{
hrCreateIndex = E_FAIL;
break;
}
ReleaseDBID(pIndexID, TRUE);
// Create the next possible index
hrCreateIndex = CreateIndex(pTableID, NULL, m_cIndexColumnDesc,
pIndexColumnDesc, cPropSets, pPropSets, &pIndexID, TRUE);
} // Next supported index column set
// Make sure we got a valid error return from CreateIndex
// If the provider doesn't support property -> DB_E_ERRORSOCCURRED
// If other error occurs (duplicate column in index) -> E_FAIL
// The IIndexDef test should be checking for these.
if (hrCreateIndex != DB_E_ERRORSOCCURRED)
CHECK(hrCreateIndex, E_FAIL);
// Reset hrCreateIndex for next prop val
hrCreateIndex = S_OK;
FreeProperties(&cPropSets, &pPropSets);
// Reset the index col DBIDs. These are pointers to the CCol DBID
// so we don't want to release them.
memset(pIndexColumnDesc, 0, (size_t)(sizeof(DBINDEXCOLUMNDESC)*m_cIndexColumnDesc));
} // Next index creation value
CLEANUP:
FreeProperties(&m_cPropSets, &m_rgPropSets);
SAFE_FREE(pIndexColumnDesc);
TRETURN
}
// }} TCW_VAR_PROTOTYPE_END
// {{ TCW_VAR_PROTOTYPE(5)
//*-----------------------------------------------------------------------
// @mfunc DBPROP_INDEX_SORTBOOKMARKS
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCProp_SingCol::Variation_5()
{
TBEGIN
HRESULT hr;
CDBID dbidNew(DBKIND_NAME, MakeObjectName(L"IAlterIn", m_cMaxIndexName));
CHECK_MEMORY(dbidNew.uName.pwszName);
//Set prop as required.
SetProperty(DBPROP_INDEX_SORTBOOKMARKS, DBPROPSET_INDEX, &m_cPropSets, &m_rgPropSets, (void*)VARIANT_TRUE, DBTYPE_BOOL, DBPROPOPTIONS_REQUIRED);
// Try to alter with this prop
TEST2C_(hr = AlterIndex(m_pIndexID, &dbidNew), S_OK, DB_E_ERRORSOCCURRED)
// Verify the prop status based on settability, etc.
TESTC(VerifyPropStatus(m_cPropSets, m_rgPropSets, DBPROP_INDEX_SORTBOOKMARKS, DBPROPSET_INDEX, DBPROPSTATUS_OK))
// Verify the index bookmark behavior. At this time I don't see a lot of utility
// in verifying this for the amount of work required.
// VerifySortBookmarks(hr, m_pTableID, m_pIndexID);
CLEANUP:
Refresh_m_pIndexID(hr, dbidNew);
ReleaseDBID(&dbidNew, FALSE);
FreeProperties(&m_cPropSets, &m_rgPropSets);
TRETURN
}
// }} TCW_VAR_PROTOTYPE_END
// {{ TCW_VAR_PROTOTYPE(6)
//*-----------------------------------------------------------------------
// @mfunc DBPROP_INDEX_TEMPINDEX
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCProp_SingCol::Variation_6()
{
TBEGIN
HRESULT hr, hrCreateIndex = S_OK;
ULONG iVal, iCreateVal;
ULONG cIndexes = 0;
VARIANT_BOOL vbCurrentValue = VARIANT_FALSE;
ULONG cPropSets = 0;
DBPROPSET * pPropSets = NULL;
DBPROPSTATUS stExpected = DBPROPSTATUS_OK;
DBID * pTableID = &(m_pTable->GetTableIDRef());
CIndexInfo IndexInfo;
IUnknown * pSessionIUnknown = NULL;
BOOL fExists = FALSE;
DBINDEXCOLUMNDESC *pIndexColumnDesc = NULL;
// Initialize pIndexColumnDesc
SAFE_ALLOC(pIndexColumnDesc, DBINDEXCOLUMNDESC, m_cIndexColumnDesc);
memset(pIndexColumnDesc, 0, (size_t)(sizeof(DBINDEXCOLUMNDESC)*m_cIndexColumnDesc));
// Save the existing IAlterIndex object. Note session object for IIndexDefinition
// is unaltered, thus index is created by a different session than we alter it with.
pSessionIUnknown = m_pIAlterIndex;
m_pIAlterIndex = NULL;
// Because of Jolt behavior wrt setting only to default value with
// AlterIndex we need to loop through all values of the property and attempt
// to create an index with that property value first.
for (iCreateVal = 0; iCreateVal < NUMELEM(VariantBoolVals); iCreateVal++)
{
// Set the property values for index creation
SetProperty(DBPROP_INDEX_TEMPINDEX, DBPROPSET_INDEX, &cPropSets, &pPropSets, (void*)VariantBoolVals[iCreateVal], DBTYPE_BOOL, DBPROPOPTIONS_REQUIRED);
// Create an index with this property set to the proper value. We assume
// failure to support the property value is valid and tested in IIndexDef
// test, so just allow failure.
hrCreateIndex = CreateIndex(pTableID, NULL, m_cIndexColumnDesc,
pIndexColumnDesc, cPropSets, pPropSets, &m_pIndexID);
cIndexes = 0;
while(hrCreateIndex == S_OK)
{
cIndexes++;
// Get information about this index.
TESTC(IndexInfo.Init(m_pIOpenRowset, pTableID, m_pIndexID));
// Set current TEMPINDEX value
vbCurrentValue = VariantBoolVals[iCreateVal];
for (iVal = 0; iVal < NUMELEM(VariantBoolVals); iVal++)
{
// Create a new session object we can release below
if (!m_pIAlterIndex)
TESTC_(GetSessionObject(IID_IAlterIndex, (IUnknown **)&m_pIAlterIndex), S_OK);
// For some providers AlterIndex can only set a property to it's current value
// so set expected prop status appropriately
if (vbCurrentValue != VariantBoolVals[iVal] && m_fSetOnlyDefault)
stExpected = DBPROPSTATUS_NOTSETTABLE;
else
stExpected = DBPROPSTATUS_OK;
//Set prop as required.
SetProperty(DBPROP_INDEX_TEMPINDEX, DBPROPSET_INDEX, &m_cPropSets, &m_rgPropSets, (void*)VariantBoolVals[iVal], DBTYPE_BOOL, DBPROPOPTIONS_REQUIRED);
// Try to alter with this prop
hr = AlterIndex(m_pIndexID, NULL);
// Allow DB_E_ERRORSOCCURRED or S_OK
if (hr != DB_E_ERRORSOCCURRED)
CHECK(hr, S_OK);
// Verify the prop status based on settability, etc.
COMPARE(VerifyPropStatus(m_cPropSets, m_rgPropSets, DBPROP_INDEX_TEMPINDEX, DBPROPSET_INDEX, stExpected), TRUE);
// This should drop the temp index if it's a temp index
SAFE_RELEASE(m_pIAlterIndex);
// Find out if the index exists
TESTC_(DoesIndexExist(pTableID, m_pIndexID, &fExists), S_OK);
// Verify temp index
if (SUCCEEDED(hr) && VariantBoolVals[iVal] == VARIANT_TRUE)
{
if (COMPARE(fExists, FALSE))
{
// We must recreate index for next alteration value
hrCreateIndex = CreateIndex(pTableID, NULL, m_cIndexColumnDesc,
pIndexColumnDesc, cPropSets, pPropSets, &m_pIndexID);
// This must always succeed, since it succeeded previously
TESTC_(hrCreateIndex, S_OK);
}
}
else
// IAlterIndex failed, or the index is not a temp index, must exist
COMPARE(fExists, TRUE);
FreeProperties(&m_cPropSets, &m_rgPropSets);
} // Next alteration value
// Drop the index we created
CHECK(m_pIIndexDef->DropIndex(pTableID, m_pIndexID), S_OK);
// Only test the maximum index count to speed up testing when using multipart
// keys
if (cIndexes >= MAX_INDEX_COUNT)
{
hrCreateIndex = E_FAIL;
break;
}
// Create the next possible index
hrCreateIndex = CreateIndex(pTableID, NULL, m_cIndexColumnDesc,
pIndexColumnDesc, cPropSets, pPropSets, &m_pIndexID, TRUE);
} // Next supported index column set
// Make sure we got a valid error return from CreateIndex
// If the provider doesn't support property -> DB_E_ERRORSOCCURRED
// If other error occurs (duplicate column in index) -> E_FAIL
// The IIndexDef test should be checking for these.
if (hrCreateIndex != DB_E_ERRORSOCCURRED)
CHECK(hrCreateIndex, E_FAIL);
// Reset hrCreateIndex for next prop val
hrCreateIndex = S_OK;
FreeProperties(&cPropSets, &pPropSets);
// Reset the index col DBIDs. These are pointers to the CCol DBID
// so we don't want to release them.
memset(pIndexColumnDesc, 0, (size_t)(sizeof(DBINDEXCOLUMNDESC)*m_cIndexColumnDesc));
} // Next index creation value
CLEANUP:
SAFE_RELEASE(m_pIAlterIndex);
m_pIAlterIndex = (IAlterIndex *)pSessionIUnknown;
FreeProperties(&m_cPropSets, &m_rgPropSets);
TRETURN
}
// }} TCW_VAR_PROTOTYPE_END
// {{ TCW_VAR_PROTOTYPE(7)
//*-----------------------------------------------------------------------
// @mfunc DBPROP_INDEX_TYPE
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCProp_SingCol::Variation_7()
{
TBEGIN
HRESULT hr;
ULONG iVal;
// TODO: Get the current value of the prop so we can determine setting r/o
// prop to current value is S_OK. Actually, due to behavior of some providers,
// we need to attempt to create an index of each type and then alter to every
// other type.
for (iVal = 0; iVal < NUMELEM(IndexTypeVals); iVal++)
{
//Set prop as required.
SetProperty(DBPROP_INDEX_TYPE, DBPROPSET_INDEX, &m_cPropSets, &m_rgPropSets, (void*)(ULONG_PTR)IndexTypeVals[iVal].ulPropVal, DBTYPE_I4, DBPROPOPTIONS_REQUIRED);
// Try to alter with this prop
hr = AlterIndex(m_pIndexID, NULL);
// Allow DB_E_ERRORSOCCURRED or S_OK
if (hr != DB_E_ERRORSOCCURRED)
CHECK(hr, S_OK);
if (S_OK == hr)
odtLog << IndexTypeVals[iVal].pwszPropVal << ":\tSUPPORTED \n";
else
odtLog << IndexTypeVals[iVal].pwszPropVal << ":\tUNSUPPORTED \n";
// Verify the prop status based on settability, etc.
COMPARE(VerifyPropStatus(m_cPropSets, m_rgPropSets, DBPROP_INDEX_TYPE, DBPROPSET_INDEX, DBPROPSTATUS_OK), TRUE);
// Verify the type. This looks pretty provider-specific, so we won't test here.
// Free props for the next time
FreeProperties(&m_cPropSets, &m_rgPropSets);
}
FreeProperties(&m_cPropSets, &m_rgPropSets);
TRETURN
}
// }} TCW_VAR_PROTOTYPE_END
// {{ TCW_VAR_PROTOTYPE(8)
//*-----------------------------------------------------------------------
// @mfunc DBPROP_INDEX_UNIQUE
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCProp_SingCol::Variation_8()
{
TBEGIN
HRESULT hr, hrCreateIndex = S_OK;
ULONG iVal, iCreateVal;
ULONG cIndexes = 0;
VARIANT_BOOL vbCurrentValue = VARIANT_FALSE;
ULONG cPropSets = 0;
DBPROPSET * pPropSets = NULL;
DBPROPSTATUS stExpected = DBPROPSTATUS_OK;
DBID * pNewIndexID = NULL;
DBID * pTableID = &(m_pTable->GetTableIDRef());
CIndexInfo IndexInfo;
DBINDEXCOLUMNDESC *pIndexColumnDesc = NULL;
// Initialize pIndexColumnDesc
SAFE_ALLOC(pIndexColumnDesc, DBINDEXCOLUMNDESC, m_cIndexColumnDesc);
memset(pIndexColumnDesc, 0, (size_t)(sizeof(DBINDEXCOLUMNDESC)*m_cIndexColumnDesc));
// Because of Jolt behavior wrt setting only to default value with
// AlterIndex we need to loop through all values of the property and attempt
// to create an index with that property value first.
for (iCreateVal = 0; iCreateVal < NUMELEM(VariantBoolVals); iCreateVal++)
{
// Set the property values for index creation
SetProperty(DBPROP_INDEX_UNIQUE, DBPROPSET_INDEX, &cPropSets, &pPropSets, (void*)VariantBoolVals[iCreateVal], DBTYPE_BOOL, DBPROPOPTIONS_REQUIRED);
// Create an index with this property set to the proper value. We assume
// failure to support the property value is valid and tested in IIndexDef
// test, so just allow failure.
hrCreateIndex = CreateIndex(pTableID, NULL, m_cIndexColumnDesc,
pIndexColumnDesc, cPropSets, pPropSets, &pNewIndexID);
cIndexes = 0;
while(hrCreateIndex == S_OK)
{
cIndexes++;
// Get information about this index.
TESTC(IndexInfo.Init(m_pIOpenRowset, pTableID, pNewIndexID));
// Read current UNIQUE value for first column of index (0 based).
vbCurrentValue = *(VARIANT_BOOL *)IndexInfo.GetIndexValuePtr(0, IS_UNIQUE);
// If index creation succeeded we'd better have the value we asked for
TESTC(vbCurrentValue == VariantBoolVals[iCreateVal]);
for (iVal = 0; iVal < NUMELEM(VariantBoolVals); iVal++)
{
// For some providers AlterIndex can only set a property to it's current value
// so set expected prop status appropriately
if (vbCurrentValue != VariantBoolVals[iVal] && m_fSetOnlyDefault)
stExpected = DBPROPSTATUS_NOTSETTABLE;
else
stExpected = DBPROPSTATUS_OK;
//Set prop as required.
SetProperty(DBPROP_INDEX_UNIQUE, DBPROPSET_INDEX, &m_cPropSets, &m_rgPropSets, (void*)VariantBoolVals[iVal], DBTYPE_BOOL, DBPROPOPTIONS_REQUIRED);
// Try to alter with this prop
hr = AlterIndex(pNewIndexID, NULL);
// Allow DB_E_ERRORSOCCURRED or S_OK
if (hr != DB_E_ERRORSOCCURRED)
CHECK(hr, S_OK);
// Verify the prop status based on settability, etc.
COMPARE(VerifyPropStatus(m_cPropSets, m_rgPropSets, DBPROP_INDEX_UNIQUE, DBPROPSET_INDEX, stExpected), TRUE);
// Verify the unique handling
VerifyUnique(hr,
m_pTable,
pNewIndexID,
VariantBoolVals[iVal],
m_cIndexColumnDesc,
pIndexColumnDesc
);
FreeProperties(&m_cPropSets, &m_rgPropSets);
} // Next alteration value
// Drop the index we created
CHECK(m_pIIndexDef->DropIndex(pTableID, pNewIndexID), S_OK);
ReleaseDBID(pNewIndexID, TRUE);
pNewIndexID = NULL;
// Only test the maximum index count to speed up testing when using multipart
// keys
if (cIndexes >= MAX_INDEX_COUNT)
{
hrCreateIndex = E_FAIL;
break;
}
// Create the next possible index
hrCreateIndex = CreateIndex(pTableID, NULL, m_cIndexColumnDesc,
pIndexColumnDesc, cPropSets, pPropSets, &pNewIndexID, TRUE);
} // Next supported index column set
// Make sure we got a valid error return from CreateIndex
// If the provider doesn't support property -> DB_E_ERRORSOCCURRED
// If other error occurs (duplicate column in index) -> E_FAIL
// The IIndexDef test should be checking for these.
if (hrCreateIndex != DB_E_ERRORSOCCURRED)
CHECK(hrCreateIndex, E_FAIL);
// Reset hrCreateIndex for next prop val
hrCreateIndex = S_OK;
FreeProperties(&cPropSets, &pPropSets);
// Reset the index col DBIDs. These are pointers to the CCol DBID
// so we don't want to release them.
memset(pIndexColumnDesc, 0, (size_t)(sizeof(DBINDEXCOLUMNDESC)*m_cIndexColumnDesc));
} // Next index creation value
CLEANUP:
SAFE_FREE(pIndexColumnDesc);
FreeProperties(&cPropSets, &pPropSets);
FreeProperties(&m_cPropSets, &m_rgPropSets);
ReleaseDBID(pNewIndexID, TRUE);
TRETURN
}
// }} TCW_VAR_PROTOTYPE_END
// {{ TCW_VAR_PROTOTYPE(9)
//*-----------------------------------------------------------------------
// @mfunc DBPROP_INDEX_FILLFACTOR
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCProp_SingCol::Variation_9()
{
TBEGIN
HRESULT hr;
CDBID dbidNew(DBKIND_NAME, MakeObjectName(L"IAlterIn", m_cMaxIndexName));
DBPROPSTATUS dbpropstat = DBPROPSTATUS_OK;
CHECK_MEMORY(dbidNew.uName.pwszName);
//Set prop as required.
//TODO: Note this prop has valid values 1-100 for B+ tree index. Need to test
//boundary cases also. And for linear hash index we're not sure what values are
//valid, needs more investigation.
// Set to max (100)
SetProperty(DBPROP_INDEX_FILLFACTOR, DBPROPSET_INDEX, &m_cPropSets, &m_rgPropSets, (void*)100, DBTYPE_I4, DBPROPOPTIONS_REQUIRED);
// Try to alter with this prop
TEST2C_(hr = AlterIndex(m_pIndexID, &dbidNew), S_OK, DB_E_ERRORSOCCURRED)
Refresh_m_pIndexID(hr, dbidNew);
// Verify the prop status based on settability, etc.
TESTC(VerifyPropStatus(m_cPropSets, m_rgPropSets, DBPROP_INDEX_FILLFACTOR, DBPROPSET_INDEX, DBPROPSTATUS_OK))
// Looks like verifying fill factor will be very provider-specific and so we won't
// attempt here.
FreeProperties(&m_cPropSets, &m_rgPropSets);
// Set to min (1)
SetProperty(DBPROP_INDEX_FILLFACTOR, DBPROPSET_INDEX, &m_cPropSets, &m_rgPropSets, (void*)1, DBTYPE_I4, DBPROPOPTIONS_REQUIRED);
// Try to alter with this prop
TEST2C_(hr = AlterIndex(m_pIndexID, NULL), S_OK, DB_E_ERRORSOCCURRED)
// Verify the prop status based on settability, etc.
TESTC(VerifyPropStatus(m_cPropSets, m_rgPropSets, DBPROP_INDEX_FILLFACTOR, DBPROPSET_INDEX, DBPROPSTATUS_OK))
FreeProperties(&m_cPropSets, &m_rgPropSets);
// If we successfully set the prop above, then it's supported, therefore we should get
// BADVALUE for the following.
if (S_OK == hr)
dbpropstat = DBPROPSTATUS_BADVALUE;
// Set to invalid (101)
SetProperty(DBPROP_INDEX_FILLFACTOR, DBPROPSET_INDEX, &m_cPropSets, &m_rgPropSets, (void*)101, DBTYPE_I4, DBPROPOPTIONS_REQUIRED);
// Try to alter with this prop
TESTC_(hr = AlterIndex(m_pIndexID, NULL), DB_E_ERRORSOCCURRED)
// Verify the prop status based on settability, etc.
TESTC(VerifyPropStatus(m_cPropSets, m_rgPropSets, DBPROP_INDEX_FILLFACTOR, DBPROPSET_INDEX, dbpropstat))
FreeProperties(&m_cPropSets, &m_rgPropSets);
// Set to invalid (0)
SetProperty(DBPROP_INDEX_FILLFACTOR, DBPROPSET_INDEX, &m_cPropSets, &m_rgPropSets, (void*)0, DBTYPE_I4, DBPROPOPTIONS_REQUIRED);
// Try to alter with this prop
TESTC_(hr = AlterIndex(m_pIndexID, NULL), DB_E_ERRORSOCCURRED)
// Verify the prop status based on settability, etc.
TESTC(VerifyPropStatus(m_cPropSets, m_rgPropSets, DBPROP_INDEX_FILLFACTOR, DBPROPSET_INDEX, dbpropstat))
CLEANUP:
Refresh_m_pIndexID(hr, dbidNew);
ReleaseDBID(&dbidNew, FALSE);
FreeProperties(&m_cPropSets, &m_rgPropSets);
TRETURN
}
// }} TCW_VAR_PROTOTYPE_END
// {{ TCW_VAR_PROTOTYPE(10)
//*-----------------------------------------------------------------------
// @mfunc DBPROP_INDEX_INITIALSIZE
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCProp_SingCol::Variation_10()
{
TBEGIN
HRESULT hr;
DBPROPSTATUS dbpropstat = DBPROPSTATUS_OK;
//Set prop as required. INITIALSIZE is the number of bytes allocated for the index
// structure. We should try 0, 1, and some large size. This is very provider
// specific.
// Set to max (10K)??? TODO: How do I know what the max size is? Do I really want
// to set a "max" size, as there may be limits such as it has to fit in available memory
// or disk space. I chose 10K as a "moderate" size likely to be supported.
SetProperty(DBPROP_INDEX_INITIALSIZE, DBPROPSET_INDEX, &m_cPropSets, &m_rgPropSets, (void*)10000, DBTYPE_I4, DBPROPOPTIONS_REQUIRED);
// Try to alter with this prop
TEST2C_(hr = AlterIndex(m_pIndexID, NULL), S_OK, DB_E_ERRORSOCCURRED)
// Verify the prop status based on settability, etc.
TESTC(VerifyPropStatus(m_cPropSets, m_rgPropSets, DBPROP_INDEX_INITIALSIZE, DBPROPSET_INDEX, DBPROPSTATUS_OK))
// Looks like verifying initialsize will be very provider-specific and so we won't
// attempt here.
FreeProperties(&m_cPropSets, &m_rgPropSets);
// If we successfully set the prop above, then it's supported, therefore we should get
// BADVALUE for the following.
if (S_OK == hr)
dbpropstat = DBPROPSTATUS_BADVALUE;
// Set to min (0). May or may not be supported.
SetProperty(DBPROP_INDEX_INITIALSIZE, DBPROPSET_INDEX, &m_cPropSets, &m_rgPropSets, (void*)0, DBTYPE_I4, DBPROPOPTIONS_REQUIRED);
// Try to alter with this prop
TEST2C_(hr = AlterIndex(m_pIndexID, NULL), S_OK, DB_E_ERRORSOCCURRED)
// Verify the prop status based on settability, etc.
TESTC(VerifyPropStatus(m_cPropSets, m_rgPropSets, DBPROP_INDEX_INITIALSIZE, DBPROPSET_INDEX, dbpropstat))
FreeProperties(&m_cPropSets, &m_rgPropSets);
// Set to value (1). May or may not be supported.
SetProperty(DBPROP_INDEX_INITIALSIZE, DBPROPSET_INDEX, &m_cPropSets, &m_rgPropSets, (void*)1, DBTYPE_I4, DBPROPOPTIONS_REQUIRED);
// Try to alter with this prop
TESTC_(hr = AlterIndex(m_pIndexID, NULL), DB_E_ERRORSOCCURRED)
// Verify the prop status based on settability, etc.
TESTC(VerifyPropStatus(m_cPropSets, m_rgPropSets, DBPROP_INDEX_INITIALSIZE, DBPROPSET_INDEX, dbpropstat))
FreeProperties(&m_cPropSets, &m_rgPropSets);
// Set to invalid (ULONG_MAX)
SetProperty(DBPROP_INDEX_INITIALSIZE, DBPROPSET_INDEX, &m_cPropSets, &m_rgPropSets, (void*)(ULONG_PTR)ULONG_MAX, DBTYPE_I4, DBPROPOPTIONS_REQUIRED);
// Try to alter with this prop
TESTC_(hr = AlterIndex(m_pIndexID, NULL), DB_E_ERRORSOCCURRED)
// Verify the prop status based on settability, etc.
TESTC(VerifyPropStatus(m_cPropSets, m_rgPropSets, DBPROP_INDEX_INITIALSIZE, DBPROPSET_INDEX, dbpropstat))
CLEANUP:
FreeProperties(&m_cPropSets, &m_rgPropSets);
TRETURN
}
// }} TCW_VAR_PROTOTYPE_END
// {{ TCW_VAR_PROTOTYPE(11)
//*-----------------------------------------------------------------------
// @mfunc DBPROP_INDEX_NULLCOLLATION
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCProp_SingCol::Variation_11()
{
TBEGIN
HRESULT hr, hrCreateIndex = S_OK;
ULONG iVal, iCreateVal, iOrder, cCreate=0;
ULONG ulCurrentValue = DBPROPVAL_NC_END;
ULONG cPropSets = 0;
DBPROPSET * pPropSets = NULL;
DBPROPSTATUS stExpected = DBPROPSTATUS_OK;
DBID * pTableID = &(m_pTable->GetTableIDRef());
CIndexInfo IndexInfo;
DBINDEXCOLUMNDESC *pIndexColumnDesc = NULL;
// Initialize pIndexColumnDesc
SAFE_ALLOC(pIndexColumnDesc, DBINDEXCOLUMNDESC, m_cIndexColumnDesc);
memset(pIndexColumnDesc, 0, (size_t)(sizeof(DBINDEXCOLUMNDESC)*m_cIndexColumnDesc));
// Because of Jolt behavior wrt setting only to default value with
// AlterIndex we need to loop through all values of the property and attempt
// to create an index with that property value first.
for (iCreateVal = 0; iCreateVal < NUMELEM(NullCollationVals); iCreateVal++)
{
// Set the property values for index creation
SetProperty(DBPROP_INDEX_NULLS, DBPROPSET_INDEX, &cPropSets, &pPropSets, (void*)DBPROPVAL_IN_ALLOWNULL, DBTYPE_I4, DBPROPOPTIONS_REQUIRED);
SetProperty(DBPROP_INDEX_NULLCOLLATION, DBPROPSET_INDEX, &cPropSets, &pPropSets, (void*)(ULONG_PTR)NullCollationVals[iCreateVal].ulPropVal, DBTYPE_I4, DBPROPOPTIONS_REQUIRED);
// For each possible index column ordering
for (iOrder = 0; iOrder < NUMELEM(IndexOrderVals); iOrder++)
{
// Create an index with this property set to the proper value. We assume
// failure to support the property value is valid and tested in IIndexDef
// test, so just allow failure.
hrCreateIndex = CreateIndex(pTableID, NULL, m_cIndexColumnDesc,
pIndexColumnDesc, cPropSets, pPropSets, &m_pIndexID, FALSE, TRUE,
IndexOrderVals[iOrder]);
while(hrCreateIndex == S_OK)
{
cCreate++;
// Get information about this index.
TESTC(IndexInfo.Init(m_pIOpenRowset, pTableID, m_pIndexID));
// Read current INDEX_NULLS value for first column of index (0 based).
ulCurrentValue = *(ULONG *)IndexInfo.GetIndexValuePtr(0, IS_NULL_COLLATION);
// If index creation succeeded we'd better have the value we asked for
TESTC(ulCurrentValue == NullCollationVals[iCreateVal].ulPropVal);
for (iVal = 0; iVal < NUMELEM(IndexNullVals); iVal++)
{
// For some providers AlterIndex can only set a property to it's current value
// so set expected prop status appropriately
if (ulCurrentValue != NullCollationVals[iVal].ulPropVal && m_fSetOnlyDefault)
stExpected = DBPROPSTATUS_NOTSETTABLE;
else
stExpected = DBPROPSTATUS_OK;
//Set prop as required.
SetProperty(DBPROP_INDEX_NULLCOLLATION, DBPROPSET_INDEX, &m_cPropSets, &m_rgPropSets, (void*)(ULONG_PTR)NullCollationVals[iVal].ulPropVal, DBTYPE_I4, DBPROPOPTIONS_REQUIRED);
// Try to alter with this prop
hr = AlterIndex(m_pIndexID, NULL);
// Allow DB_E_ERRORSOCCURRED or S_OK
if (hr != DB_E_ERRORSOCCURRED)
CHECK(hr, S_OK);
// Verify the prop status based on settability, etc.
COMPARE(VerifyPropStatus(m_cPropSets, m_rgPropSets, DBPROP_INDEX_NULLCOLLATION, DBPROPSET_INDEX, stExpected), TRUE);
// Verify the index null handling
VerifyNullCollation(hr,
m_pTable,
m_pIndexID,
NullCollationVals[iVal].ulPropVal,
m_cIndexColumnDesc,
pIndexColumnDesc
);
FreeProperties(&m_cPropSets, &m_rgPropSets);
} // Next alteration value
// Drop the index we created
CHECK(m_pIIndexDef->DropIndex(pTableID, m_pIndexID), S_OK);
// Create the next possible index
hrCreateIndex = CreateIndex(pTableID, NULL, m_cIndexColumnDesc,
pIndexColumnDesc, cPropSets, pPropSets, &m_pIndexID, TRUE,
TRUE, IndexOrderVals[iOrder]);
} // Next supported index column set
} // Next col order value
// Make sure we got a valid error return from CreateIndex
// If the provider doesn't support property -> DB_E_ERRORSOCCURRED
// If other error occurs (duplicate column in index) -> E_FAIL
// The IIndexDef test should be checking for these.
if (hrCreateIndex != DB_E_ERRORSOCCURRED)
CHECK(hrCreateIndex, E_FAIL);
// Reset hrCreateIndex for next prop val
hrCreateIndex = S_OK;
FreeProperties(&cPropSets, &pPropSets);
// Reset the index col DBIDs. These are pointers to the CCol DBID
// so we don't want to release them.
memset(pIndexColumnDesc, 0, (size_t)(sizeof(DBINDEXCOLUMNDESC)*m_cIndexColumnDesc));
} // Next index creation value
CLEANUP:
if (!cCreate)
{
odtLog << L"Unable to create any indexes to test this property.\n";
TESTB = TEST_SKIPPED;
}
FreeProperties(&m_cPropSets, &m_rgPropSets);
TRETURN
}
// }} TCW_VAR_PROTOTYPE_END
// {{ TCW_VAR_PROTOTYPE(12)
//*-----------------------------------------------------------------------
// @mfunc DBPROP_INDEX_SORTBOOKMARKS and DBPROP_INDEX_UNIQUE
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCProp_SingCol::Variation_12()
{
TBEGIN
HRESULT hr;
CIndexInfo IndexInfo;
VARIANT_BOOL vbUnique = 100;
VARIANT_BOOL vbSort = 100;
ULONG iUniqueVal, iSortVal;
DBPROPSTATUS stUnique, stSort;
// Get information about this index.
TESTC(IndexInfo.Init(m_pIOpenRowset, &(m_pTable->GetTableID()), m_pIndexID));
// Read current autoupdate value for first column of index (0 based).
vbUnique = *(VARIANT_BOOL *)IndexInfo.GetIndexValuePtr(0, IS_UNIQUE);
vbSort = *(VARIANT_BOOL *)IndexInfo.GetIndexValuePtr(0, IS_SORT_BOOKMARKS);
for (iUniqueVal = 0; iUniqueVal < NUMELEM(VariantBoolVals); iUniqueVal++)
{
for (iSortVal = 0; iSortVal < NUMELEM(VariantBoolVals); iSortVal++)
{
// For some providers AlterIndex can only set a property to it's current value
// so set expected prop status appropriately
if (vbUnique != VariantBoolVals[iUniqueVal] && m_fSetOnlyDefault)
stUnique = DBPROPSTATUS_NOTSETTABLE;
else
stUnique = DBPROPSTATUS_OK;
if (vbSort != VariantBoolVals[iSortVal] && m_fSetOnlyDefault)
stSort = DBPROPSTATUS_NOTSETTABLE;
else
stSort = DBPROPSTATUS_OK;
//Set prop.
SetProperty(DBPROP_INDEX_UNIQUE, DBPROPSET_INDEX, &m_cPropSets, &m_rgPropSets, (void*)VariantBoolVals[iUniqueVal], DBTYPE_BOOL, DBPROPOPTIONS_REQUIRED);
SetProperty(DBPROP_INDEX_SORTBOOKMARKS, DBPROPSET_INDEX, &m_cPropSets, &m_rgPropSets, (void*)VariantBoolVals[iSortVal], DBTYPE_BOOL, DBPROPOPTIONS_REQUIRED);
// If this val matches the initial values it should always succeed
if (VariantBoolVals[iUniqueVal] == vbUnique &&
VariantBoolVals[iSortVal] == vbSort)
{
// Try to alter with this prop
TESTC_(hr = AlterIndex(m_pIndexID, NULL), S_OK)
}
else
{
// Try to alter with this prop
TEST2C_(hr = AlterIndex(m_pIndexID, NULL), S_OK, DB_E_ERRORSOCCURRED)
}
// Verify the prop status based on settability, etc.
TESTC(VerifyPropStatus(m_cPropSets, m_rgPropSets, DBPROP_INDEX_UNIQUE, DBPROPSET_INDEX, stUnique))
TESTC(VerifyPropStatus(m_cPropSets, m_rgPropSets, DBPROP_INDEX_SORTBOOKMARKS, DBPROPSET_INDEX, stSort))
// If prop is VARIANT_TRUE, verify the index works as requested.
// Since we already verify this for the single prop case and it's kinda
// slow we'll leave commented out until code review time. I'd like to
// remove this if we agree it's redundant.
// VerifyUnique(hr, m_pTableID, m_pIndexID);
// VerifySortBookmarks(hr, m_pTable, m_pIndexID);
FreeProperties(&m_cPropSets, &m_rgPropSets);
}
}
CLEANUP:
FreeProperties(&m_cPropSets, &m_rgPropSets);
TRETURN
}
// }} TCW_VAR_PROTOTYPE_END
// {{ TCW_VAR_PROTOTYPE(13)
//*-----------------------------------------------------------------------
// @mfunc DBPROP_INDEX_UNIQUE and DBPROP_INDEX_PRIMARYKEY
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCProp_SingCol::Variation_13()
{
TBEGIN
HRESULT hr;
CIndexInfo IndexInfo;
VARIANT_BOOL vbUnique = 100;
VARIANT_BOOL vbPrimary = 100;
ULONG iUniqueVal, iPrimaryVal;
DBPROPSTATUS stUnique, stPrimary;
// Get information about this index.
TESTC(IndexInfo.Init(m_pIOpenRowset, &(m_pTable->GetTableID()), m_pIndexID));
// Read current autoupdate value for first column of index (0 based).
vbUnique = *(VARIANT_BOOL *)IndexInfo.GetIndexValuePtr(0, IS_UNIQUE);
vbPrimary = *(VARIANT_BOOL *)IndexInfo.GetIndexValuePtr(0, IS_PRIMARY_KEY);
for (iUniqueVal = 0; iUniqueVal < NUMELEM(VariantBoolVals); iUniqueVal++)
{
for (iPrimaryVal = 0; iPrimaryVal < NUMELEM(VariantBoolVals); iPrimaryVal++)
{
// For some providers AlterIndex can only set a property to it's current value
// so set expected prop status appropriately
if (vbUnique != VariantBoolVals[iUniqueVal] && m_fSetOnlyDefault)
stUnique = DBPROPSTATUS_NOTSETTABLE;
else
stUnique = DBPROPSTATUS_OK;
if (vbPrimary != VariantBoolVals[iPrimaryVal] && m_fSetOnlyDefault)
stPrimary = DBPROPSTATUS_NOTSETTABLE;
else
stPrimary = DBPROPSTATUS_OK;
//Set prop.
SetProperty(DBPROP_INDEX_UNIQUE, DBPROPSET_INDEX, &m_cPropSets, &m_rgPropSets, (void*)VariantBoolVals[iUniqueVal], DBTYPE_BOOL, DBPROPOPTIONS_REQUIRED);
SetProperty(DBPROP_INDEX_PRIMARYKEY, DBPROPSET_INDEX, &m_cPropSets, &m_rgPropSets, (void*)VariantBoolVals[iPrimaryVal], DBTYPE_BOOL, DBPROPOPTIONS_REQUIRED);
// If this val matches the initial values it should always succeed
if (VariantBoolVals[iUniqueVal] == vbUnique &&
VariantBoolVals[iPrimaryVal] == vbPrimary)
{
// Try to alter with this prop
TESTC_(hr = AlterIndex(m_pIndexID, NULL), S_OK)
}
else
{
// Try to alter with this prop
TEST2C_(hr = AlterIndex(m_pIndexID, NULL), S_OK, DB_E_ERRORSOCCURRED)
}
// Verify the prop status based on settability, etc.
TESTC(VerifyPropStatus(m_cPropSets, m_rgPropSets, DBPROP_INDEX_UNIQUE, DBPROPSET_INDEX, stUnique))
TESTC(VerifyPropStatus(m_cPropSets, m_rgPropSets, DBPROP_INDEX_PRIMARYKEY, DBPROPSET_INDEX, stPrimary))
// If prop is VARIANT_TRUE, verify the index works as requested.
// Since we already verify this for the single prop case and it's kinda
// slow we'll leave commented out until code review time. I'd like to
// remove this if we agree it's redundant.
// VerifyUnique(hr, m_pTable, m_pIndexID);
// VerifyPrimaryKey(hr, m_pTable, m_pIndexID);
FreeProperties(&m_cPropSets, &m_rgPropSets);
}
}
CLEANUP:
FreeProperties(&m_cPropSets, &m_rgPropSets);
TRETURN
}
// }} TCW_VAR_PROTOTYPE_END
// {{ TCW_VAR_PROTOTYPE(14)
//*-----------------------------------------------------------------------
// @mfunc DBPROP_INDEX_UNIQUE and DBPROP_INDEX_NULLS
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCProp_SingCol::Variation_14()
{
TBEGIN
HRESULT hr;
CIndexInfo IndexInfo;
VARIANT_BOOL vbUnique = 100;
ULONG ulNull = 100;
ULONG iUniqueVal, iNullVal;
DBPROPSTATUS stUnique, stNull;
// Get information about this index.
TESTC(IndexInfo.Init(m_pIOpenRowset, &(m_pTable->GetTableID()), m_pIndexID));
// Read current UNIQUE and NULLS value for first column of index (0 based).
TESTC(IndexInfo.IsIndexValueValid(0, IS_UNIQUE));
vbUnique = *(VARIANT_BOOL *)IndexInfo.GetIndexValuePtr(0, IS_UNIQUE);
TESTC(IndexInfo.IsIndexValueValid(0, IS_NULLS));
ulNull = *(VARIANT_BOOL *)IndexInfo.GetIndexValuePtr(0, IS_NULLS);
for (iUniqueVal = 0; iUniqueVal < NUMELEM(VariantBoolVals); iUniqueVal++)
{
for (iNullVal = 0; iNullVal < NUMELEM(IndexNullVals); iNullVal++)
{
// For some providers AlterIndex can only set a property to it's current value
// so set expected prop status appropriately
if (vbUnique != VariantBoolVals[iUniqueVal] && m_fSetOnlyDefault)
stUnique = DBPROPSTATUS_NOTSETTABLE;
else
stUnique = DBPROPSTATUS_OK;
if (ulNull != IndexNullVals[iNullVal].ulPropVal && m_fSetOnlyDefault)
stNull = DBPROPSTATUS_NOTSETTABLE;
else
stNull = DBPROPSTATUS_OK;
//Set prop.
SetProperty(DBPROP_INDEX_UNIQUE, DBPROPSET_INDEX, &m_cPropSets, &m_rgPropSets, (void*)VariantBoolVals[iUniqueVal], DBTYPE_BOOL, DBPROPOPTIONS_REQUIRED);
SetProperty(DBPROP_INDEX_NULLS, DBPROPSET_INDEX, &m_cPropSets, &m_rgPropSets, (void*)(ULONG_PTR)IndexNullVals[iNullVal].ulPropVal, DBTYPE_I4, DBPROPOPTIONS_REQUIRED);
// If this val matches the initial values it should always succeed
if (VariantBoolVals[iUniqueVal] == vbUnique &&
IndexNullVals[iNullVal].ulPropVal == ulNull)
{
// Try to alter with this prop
TESTC_(hr = AlterIndex(m_pIndexID, NULL), S_OK)
}
else
{
// Try to alter with this prop
TEST2C_(hr = AlterIndex(m_pIndexID, NULL), S_OK, DB_E_ERRORSOCCURRED)
}
// Verify the prop status based on settability, etc.
TESTC(VerifyPropStatus(m_cPropSets, m_rgPropSets, DBPROP_INDEX_UNIQUE, DBPROPSET_INDEX, stUnique))
TESTC(VerifyPropStatus(m_cPropSets, m_rgPropSets, DBPROP_INDEX_NULLS, DBPROPSET_INDEX, stNull))
// If prop is VARIANT_TRUE, verify the index works as requested.
// Since we already verify this for the single prop case and it's kinda
// slow we'll leave commented out until code review time. I'd like to
// remove this if we agree it's redundant.
// VerifyUnique(hr, m_pTable, m_pIndexID);
// VerifyNulls(hr, m_pTable, m_pIndexID);
FreeProperties(&m_cPropSets, &m_rgPropSets);
}
}
CLEANUP:
FreeProperties(&m_cPropSets, &m_rgPropSets);
TRETURN
}
// }} TCW_VAR_PROTOTYPE_END
// {{ TCW_VAR_PROTOTYPE(15)
//*-----------------------------------------------------------------------
// @mfunc DBPROP_INDEX_NULLS and DBPROP_INDEX_PRIMARYKEY
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCProp_SingCol::Variation_15()
{
TBEGIN
HRESULT hr;
CIndexInfo IndexInfo;
VARIANT_BOOL vbPrimary = 100;
ULONG ulNull = 100;
ULONG iPrimaryVal, iNullVal;
DBPROPSTATUS stPrimary, stNull;
// Get information about this index.
TESTC(IndexInfo.Init(m_pIOpenRowset, &(m_pTable->GetTableID()), m_pIndexID));
// Read current autoupdate value for first column of index (0 based).
TESTC(IndexInfo.IsIndexValueValid(0, IS_PRIMARY_KEY));
vbPrimary = *(VARIANT_BOOL *)IndexInfo.GetIndexValuePtr(0, IS_PRIMARY_KEY);
TESTC(IndexInfo.IsIndexValueValid(0, IS_NULLS));
ulNull = *(VARIANT_BOOL *)IndexInfo.GetIndexValuePtr(0, IS_NULLS);
for (iPrimaryVal = 0; iPrimaryVal < NUMELEM(VariantBoolVals); iPrimaryVal++)
{
for (iNullVal = 0; iNullVal < NUMELEM(IndexNullVals); iNullVal++)
{
// For some providers AlterIndex can only set a property to it's current value
// so set expected prop status appropriately
if (vbPrimary != VariantBoolVals[iPrimaryVal] && m_fSetOnlyDefault)
stPrimary = DBPROPSTATUS_NOTSETTABLE;
else
stPrimary = DBPROPSTATUS_OK;
if (ulNull != IndexNullVals[iNullVal].ulPropVal && m_fSetOnlyDefault)
stNull = DBPROPSTATUS_NOTSETTABLE;
else
stNull = DBPROPSTATUS_OK;
//Set prop.
SetProperty(DBPROP_INDEX_PRIMARYKEY, DBPROPSET_INDEX, &m_cPropSets, &m_rgPropSets, (void*)VariantBoolVals[iPrimaryVal], DBTYPE_BOOL, DBPROPOPTIONS_REQUIRED);
SetProperty(DBPROP_INDEX_NULLS, DBPROPSET_INDEX, &m_cPropSets, &m_rgPropSets, (void*)(ULONG_PTR)IndexNullVals[iNullVal].ulPropVal, DBTYPE_I4, DBPROPOPTIONS_REQUIRED);
// If this val matches the initial values it should always succeed
if (VariantBoolVals[iPrimaryVal] == vbPrimary &&
IndexNullVals[iNullVal].ulPropVal == ulNull)
{
// Try to alter with this prop
TESTC_(hr = AlterIndex(m_pIndexID, NULL), S_OK)
}
else
{
// Try to alter with this prop
TEST2C_(hr = AlterIndex(m_pIndexID, NULL), S_OK, DB_E_ERRORSOCCURRED)
}
// Verify the prop status based on settability, etc.
TESTC(VerifyPropStatus(m_cPropSets, m_rgPropSets, DBPROP_INDEX_PRIMARYKEY, DBPROPSET_INDEX, stPrimary))
TESTC(VerifyPropStatus(m_cPropSets, m_rgPropSets, DBPROP_INDEX_NULLS, DBPROPSET_INDEX, stNull))
// If prop is VARIANT_TRUE, verify the index works as requested.
// VerifyPrimaryKey(hr, m_pTable, m_pIndexID);
// VerifyNulls(hr, m_pTable, m_pIndexID);
FreeProperties(&m_cPropSets, &m_rgPropSets);
}
}
CLEANUP:
FreeProperties(&m_cPropSets, &m_rgPropSets);
TRETURN
}
// }} TCW_VAR_PROTOTYPE_END
// {{ TCW_VAR_PROTOTYPE(16)
//*-----------------------------------------------------------------------
// @mfunc DB_E_ERRORSOCCURRED - Non index property with DBPROP_REQUIRED
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCProp_SingCol::Variation_16()
{
TBEGIN
HRESULT hr;
CDBID dbidNew(DBKIND_NAME, MakeObjectName(L"IAlterIn", m_cMaxIndexName));
CHECK_MEMORY(dbidNew.uName.pwszName);
//Set a non-index property required.
SetProperty(DBPROP_BOOKMARKS, DBPROPSET_ROWSET, &m_cPropSets, &m_rgPropSets, (void*)VARIANT_TRUE, DBTYPE_BOOL, DBPROPOPTIONS_REQUIRED);
// Try to alter with this prop
TESTC_(hr = AlterIndex(m_pIndexID, &dbidNew), DB_E_ERRORSOCCURRED)
// Verify the prop status based on settability, etc.
TESTC(VerifyPropStatus(m_cPropSets, m_rgPropSets, DBPROP_BOOKMARKS, DBPROPSET_ROWSET, DBPROPSTATUS_NOTSUPPORTED))
CLEANUP:
Refresh_m_pIndexID(hr, dbidNew);
ReleaseDBID(&dbidNew, FALSE);
FreeProperties(&m_cPropSets, &m_rgPropSets);
TRETURN
}
// }} TCW_VAR_PROTOTYPE_END
// {{ TCW_VAR_PROTOTYPE(17)
//*-----------------------------------------------------------------------
// @mfunc DB_S_ERRORSOCCURRED - Non index property with DBPROP_SETIFCHEAP
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCProp_SingCol::Variation_17()
{
TBEGIN
HRESULT hr;
CDBID dbidNew(DBKIND_NAME, MakeObjectName(L"IAlterIn", m_cMaxIndexName));
CHECK_MEMORY(dbidNew.uName.pwszName);
// Note that DBPROPOPTIONS_OPTIONAL and DBPROPOPTIONS_SETIFCHEAP are numerically identical
TESTC(DBPROPOPTIONS_OPTIONAL == DBPROPOPTIONS_SETIFCHEAP);
//Set a non-index property SETIFCHEAP.
SetProperty(DBPROP_BOOKMARKS, DBPROPSET_ROWSET, &m_cPropSets, &m_rgPropSets, (void*)VARIANT_TRUE, DBTYPE_BOOL, DBPROPOPTIONS_SETIFCHEAP);
// Try to alter with this prop
TESTC_(hr = AlterIndex(m_pIndexID, &dbidNew), DB_S_ERRORSOCCURRED)
// Verify the prop status based on settability, etc.
TESTC(VerifyPropStatus(m_cPropSets, m_rgPropSets, DBPROP_BOOKMARKS, DBPROPSET_ROWSET, DBPROPSTATUS_NOTSUPPORTED))
CLEANUP:
Refresh_m_pIndexID(hr, dbidNew);
ReleaseDBID(&dbidNew, FALSE);
FreeProperties(&m_cPropSets, &m_rgPropSets);
TRETURN
}
// }} TCW_VAR_PROTOTYPE_END
// {{ TCW_VAR_PROTOTYPE(18)
//*-----------------------------------------------------------------------
// @mfunc Invalid values for properties (unexpected type)
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCProp_SingCol::Variation_18()
{
TBEGIN
HRESULT hr;
ULONG iProp;
// Try for all index props
for (iProp = 0; iProp < NUMELEM(IndexProperties); iProp++)
{
//Set prop as required using DBTYPE_I2, which doesn't match any index props.
SetProperty(IndexProperties[iProp].dwProp, DBPROPSET_INDEX, &m_cPropSets, &m_rgPropSets, (void*)-1, DBTYPE_I2, DBPROPOPTIONS_REQUIRED);
// Try to alter with this prop
hr = AlterIndex(m_pIndexID, NULL);
// Allow DB_E_ERRORSOCCURRED
CHECK(hr, DB_E_ERRORSOCCURRED);
// Verify the prop status based on settability, etc.
COMPARE(VerifyPropStatus(m_cPropSets, m_rgPropSets, IndexProperties[iProp].dwProp, DBPROPSET_INDEX, DBPROPSTATUS_BADVALUE), TRUE);
// Free props for the next time
FreeProperties(&m_cPropSets, &m_rgPropSets);
}
FreeProperties(&m_cPropSets, &m_rgPropSets);
TRETURN
}
// }} TCW_VAR_PROTOTYPE_END
// {{ TCW_VAR_PROTOTYPE(19)
//*-----------------------------------------------------------------------
// @mfunc Specify a property twice
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCProp_SingCol::Variation_19()
{
TBEGIN
ULONG iPropSet, iProp;
LONG lCurrentVal = 0, lDefaultVal = 0;
DBID * pTableID = &(m_pTable->GetTableIDRef());
CIndexInfo IndexInfo;
// Get information about this index.
TESTC(IndexInfo.Init(m_pIOpenRowset, pTableID, m_pIndexID));
// See if the property is available
TESTC(IndexInfo.IsIndexValueValid(0, IS_NULLS));
// Get the default value of this property
lDefaultVal = *(LONG *)IndexInfo.GetIndexValuePtr(0, IS_NULLS);
// Set prop twice with conflicting values
SetProperty(DBPROP_INDEX_NULLS, DBPROPSET_INDEX, &m_cPropSets, &m_rgPropSets, (void*)DBPROPVAL_IN_ALLOWNULL, DBTYPE_I4, DBPROPOPTIONS_REQUIRED);
SetProperty(DBPROP_INDEX_NULLS, DBPROPSET_INDEX, &m_cPropSets, &m_rgPropSets, (void*)DBPROPVAL_IN_DISALLOWNULL, DBTYPE_I4, DBPROPOPTIONS_REQUIRED);
// Try to alter with this prop
TESTC_(AlterIndex(m_pIndexID, NULL), DB_E_ERRORSOCCURRED);
// See if the property is available
TESTC(IndexInfo.IsIndexValueValid(0, IS_NULLS));
// Get the current value of this property
lCurrentVal = *(LONG *)IndexInfo.GetIndexValuePtr(0, IS_NULLS);
// VerifyPropStatus only verifies one prop of the two, so we've got to spin through
// the props ourselves. Note since we know the propset/props we set we don't bother
// to validate propset or propid.
for (iPropSet = 0; iPropSet < m_cPropSets; iPropSet++)
{
for (iProp = 0; iProp < m_rgPropSets[iPropSet].cProperties; iProp++)
{
// See if the property status matches expected
if (m_rgPropSets[iPropSet].rgProperties[iProp].dwStatus == DBPROPSTATUS_OK)
// Must match currently set value
COMPARE(lCurrentVal, V_I4(&m_rgPropSets[iPropSet].rgProperties[iProp].vValue));
else
{
// If error status is returned this prop must not match current value
COMPARE(lCurrentVal != V_I4(&m_rgPropSets[iPropSet].rgProperties[iProp].vValue), TRUE);
// And we expect conflicting status or perhaps not settable for r/o prop
// not being set to default value.
if (m_rgPropSets[iPropSet].rgProperties[iProp].dwStatus == DBPROPSTATUS_NOTSETTABLE)
{
// This prop value must not match default value
COMPARE(lDefaultVal != V_I4(&m_rgPropSets[iPropSet].rgProperties[iProp].vValue), TRUE);
// Must not be a settable prop, or provider must not allow setting props
// via AlterIndex even if allowed on CreateIndex
COMPARE
(
!SettableProperty(DBPROP_INDEX_NULLS, DBPROPSET_INDEX, m_pThisTestModule->m_pIUnknown, SESSION_INTERFACE) ||
m_fSetOnlyDefault,
TRUE
);
}
else
COMPARE(m_rgPropSets[iPropSet].rgProperties[iProp].dwStatus, DBPROPSTATUS_CONFLICTING);
}
}
}
CLEANUP:
// Free props for the next time
FreeProperties(&m_cPropSets, &m_rgPropSets);
TRETURN
}
// }} TCW_VAR_PROTOTYPE_END
// {{ TCW_VAR_PROTOTYPE(20)
//*-----------------------------------------------------------------------
// @mfunc Set invalid value for prop (unexpected value)
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCProp_SingCol::Variation_20()
{
DBINDEXCOLUMNDESC *pIndexColumnDesc = NULL;
DBID * pTableID = &(m_pTable->GetTableIDRef());
DBID * pIndexID = NULL;
DBPROPSTATUS stExpected = DBPROPSTATUS_BADVALUE;
TBEGIN
// Initialize pIndexColumnDesc
SAFE_ALLOC(pIndexColumnDesc, DBINDEXCOLUMNDESC, m_cIndexColumnDesc);
memset(pIndexColumnDesc, 0, (size_t)(sizeof(DBINDEXCOLUMNDESC)*m_cIndexColumnDesc));
// Set the prop to valid value so we can get an alterable index
TESTC_PROVIDER(SetSettableProperty(DBPROP_INDEX_PRIMARYKEY, DBPROPSET_INDEX, &m_cPropSets, &m_rgPropSets, (void*)VARIANT_TRUE, DBTYPE_BOOL, DBPROPOPTIONS_REQUIRED));
TESTC_PROVIDER(S_OK == CreateAlterableIndex(pTableID, NULL, m_cIndexColumnDesc,
pIndexColumnDesc, m_cPropSets, m_rgPropSets, &pIndexID));
//Set prop as required using using a value of 1 (not VARIANT_TRUE or VARIANT_FALSE).
FreeProperties(&m_cPropSets, &m_rgPropSets);
SetSettableProperty(DBPROP_INDEX_PRIMARYKEY, DBPROPSET_INDEX, &m_cPropSets, &m_rgPropSets, (void*)1, DBTYPE_BOOL, DBPROPOPTIONS_REQUIRED);
// Try to alter with this prop
TESTC_(AlterIndex(m_pIndexID, NULL), DB_E_ERRORSOCCURRED);
// If the provider doesn't allow setting the prop except to default then we'll get
// NOTSETTABLE here.
if (m_fSetOnlyDefault)
stExpected = DBPROPSTATUS_NOTSETTABLE;
// Verify the prop status based on settability, etc.
TESTC(VerifyPropStatus(m_cPropSets, m_rgPropSets, DBPROP_INDEX_PRIMARYKEY, DBPROPSET_INDEX, stExpected));
CLEANUP:
CleanUpIndex(pTableID, &pIndexID, pIndexColumnDesc, &m_cPropSets, &m_rgPropSets);
TRETURN
}
// }} TCW_VAR_PROTOTYPE_END
// {{ TCW_VAR_PROTOTYPE(21)
//*-----------------------------------------------------------------------
// @mfunc Set colid for prop
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCProp_SingCol::Variation_21()
{
TBEGIN
HRESULT hr;
CDBID colid(DBKIND_NAME, MakeObjectName(L"IAlterIn", m_cMaxIndexName));
// Per spec DBPROP_INDEX_PRIMARYKEY doesn't take a colid. Make sure this is so.
TESTC(!(DBPROPFLAGS_COLUMNOK & GetPropInfoFlags(DBPROP_INDEX_PRIMARYKEY,
DBPROPSET_INDEX, m_pThisTestModule->m_pIUnknown, DATASOURCE_INTERFACE)));
TESTC(m_cPropSets == 0);
TESTC_PROVIDER(SetSettableProperty(DBPROP_INDEX_PRIMARYKEY, DBPROPSET_INDEX, &m_cPropSets, &m_rgPropSets, (void*)VARIANT_TRUE, DBTYPE_BOOL, DBPROPOPTIONS_REQUIRED, colid));
// Try to alter with this prop. Per spec colid should be ignored if no applicable.
TESTC_(hr = AlterIndex(m_pIndexID, NULL), S_OK)
// Verify the prop status based on settability, etc.
TESTC(VerifyPropStatus(m_cPropSets, m_rgPropSets, DBPROP_INDEX_PRIMARYKEY, DBPROPSET_INDEX, DBPROPSTATUS_OK))
CLEANUP:
ReleaseDBID(&colid, FALSE);
FreeProperties(&m_cPropSets, &m_rgPropSets);
TRETURN
}
// }} TCW_VAR_PROTOTYPE_END
// {{ TCW_VAR_PROTOTYPE(22)
//*-----------------------------------------------------------------------
// @mfunc Set non-index prop in DBPROPSET_INDEX
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCProp_SingCol::Variation_22()
{
TBEGIN
HRESULT hr;
TESTC(m_cPropSets == 0);
TESTC(SetProperty(DBPROP_BOOKMARKS, DBPROPSET_INDEX, &m_cPropSets, &m_rgPropSets, (void*)VARIANT_TRUE, DBTYPE_BOOL, DBPROPOPTIONS_REQUIRED));
// Try to alter with this prop
TESTC_(hr = AlterIndex(m_pIndexID, NULL), DB_E_ERRORSOCCURRED)
// Verify the prop status based on settability, etc.
TESTC(VerifyPropStatus(m_cPropSets, m_rgPropSets, DBPROP_BOOKMARKS, DBPROPSET_INDEX, DBPROPSTATUS_NOTSUPPORTED))
CLEANUP:
FreeProperties(&m_cPropSets, &m_rgPropSets);
TRETURN
}
// }} TCW_VAR_PROTOTYPE_END
// {{ TCW_VAR_PROTOTYPE(23)
//*-----------------------------------------------------------------------
// @mfunc Set array of propsets, one with 0 properties
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCProp_SingCol::Variation_23()
{
TBEGIN
HRESULT hr;
DBID * pTableID = &(m_pNoNullTable->GetTableIDRef());
DBID * pIndexID = NULL;
DBINDEXCOLUMNDESC *pIndexColumnDesc = NULL;
// Initialize pIndexColumnDesc
SAFE_ALLOC(pIndexColumnDesc, DBINDEXCOLUMNDESC, m_cIndexColumnDesc);
memset(pIndexColumnDesc, 0, (size_t)(sizeof(DBINDEXCOLUMNDESC)*m_cIndexColumnDesc));
TESTC(m_cPropSets == 0);
TESTC_PROVIDER(SetSettableProperty(DBPROP_INDEX_PRIMARYKEY, DBPROPSET_INDEX, &m_cPropSets, &m_rgPropSets, (void*)VARIANT_TRUE, DBTYPE_BOOL, DBPROPOPTIONS_REQUIRED));
// Create an index we can alter with DBPROP_INDEX_PRIMARYKEY
TESTC_PROVIDER(S_OK == CreateAlterableIndex(pTableID, NULL, m_cIndexColumnDesc,
pIndexColumnDesc, m_cPropSets, m_rgPropSets, &pIndexID));
// Create another propset entry with 0 props
TESTC_PROVIDER(SetSettableProperty(DBPROP_CANHOLDROWS, DBPROPSET_ROWSET, &m_cPropSets, &m_rgPropSets, (void*)VARIANT_TRUE, DBTYPE_BOOL, DBPROPOPTIONS_REQUIRED));
VariantClear(&(m_rgPropSets[1].rgProperties[0].vValue));
m_rgPropSets[1].cProperties = 0;
m_rgPropSets[1].guidPropertySet = DBPROPSET_INDEX;
// Try to alter with this prop
TESTC_(hr = AlterIndex(pTableID, pIndexID, (DBID *)NULL), S_OK)
// Verify the prop status based on settability, etc.
TESTC(VerifyPropStatus(m_cPropSets, m_rgPropSets, DBPROP_INDEX_PRIMARYKEY, DBPROPSET_INDEX, DBPROPSTATUS_OK))
CLEANUP:
CleanUpIndex(pTableID, &pIndexID, pIndexColumnDesc, &m_cPropSets, &m_rgPropSets);
TRETURN
}
// }} TCW_VAR_PROTOTYPE_END
// {{ TCW_VAR_PROTOTYPE(24)
//*-----------------------------------------------------------------------
// @mfunc Set props with static property sets and properties
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCProp_SingCol::Variation_24()
{
DBINDEXCOLUMNDESC *pIndexColumnDesc = NULL;
DBID * pTableID = &(m_pTable->GetTableIDRef());
DBID * pIndexID = NULL;
CVARIANT vTrue(VT_BOOL, VARIANT_TRUE);
ULONG cPropSets = 1;
DBPROP rgProperties[1];
DBPROPSET rgPropSets[1];
rgProperties[0].dwPropertyID = DBPROP_INDEX_PRIMARYKEY;
rgProperties[0].dwOptions = DBPROPOPTIONS_REQUIRED;
rgProperties[0].dwStatus = DBPROPSTATUS_OK;
rgProperties[0].colid = DB_NULLID;
rgProperties[0].vValue = vTrue;
rgPropSets[0].rgProperties = rgProperties;
rgPropSets[0].cProperties = 1;
rgPropSets[0].guidPropertySet = DBPROPSET_INDEX;
TBEGIN
// Initialize pIndexColumnDesc
SAFE_ALLOC(pIndexColumnDesc, DBINDEXCOLUMNDESC, m_cIndexColumnDesc);
memset(pIndexColumnDesc, 0, (size_t)(sizeof(DBINDEXCOLUMNDESC)*m_cIndexColumnDesc));
TESTC_PROVIDER(S_OK == CreateAlterableIndex(pTableID, NULL, m_cIndexColumnDesc,
pIndexColumnDesc, cPropSets, rgPropSets, &pIndexID));
// Try to alter with this prop
TESTC_(AlterIndex(pIndexID, NULL), S_OK);
// Verify the prop status based on settability, etc.
TESTC(VerifyPropStatus(cPropSets, rgPropSets, DBPROP_INDEX_PRIMARYKEY, DBPROPSET_INDEX, DBPROPSTATUS_OK));
CLEANUP:
CleanUpIndex(pTableID, &pIndexID, pIndexColumnDesc, &m_cPropSets, &m_rgPropSets);
TRETURN
}
// }} TCW_VAR_PROTOTYPE_END
// {{ TCW_VAR_PROTOTYPE(25)
//*-----------------------------------------------------------------------
// @mfunc Set invalid properties REQUIRED and change name, verify new name doesn't exist
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCProp_SingCol::Variation_25()
{
DBINDEXCOLUMNDESC *pIndexColumnDesc = NULL;
CDBID dbidNew(DBKIND_NAME, MakeObjectName(L"IAlterIn", m_cMaxIndexName));
DBID * pTableID = &(m_pNoNullTable->GetTableIDRef());
DBID * pIndexID = NULL;
DBPROPSTATUS stExpected = DBPROPSTATUS_BADVALUE;
TBEGIN
// Initialize pIndexColumnDesc
SAFE_ALLOC(pIndexColumnDesc, DBINDEXCOLUMNDESC, m_cIndexColumnDesc);
memset(pIndexColumnDesc, 0, (size_t)(sizeof(DBINDEXCOLUMNDESC)*m_cIndexColumnDesc));
// Set the prop to valid value so we can get an alterable index
TESTC_PROVIDER(SetSettableProperty(DBPROP_INDEX_PRIMARYKEY, DBPROPSET_INDEX, &m_cPropSets, &m_rgPropSets, (void*)VARIANT_TRUE, DBTYPE_BOOL, DBPROPOPTIONS_REQUIRED));
TESTC_PROVIDER(S_OK == CreateAlterableIndex(pTableID, NULL, m_cIndexColumnDesc,
pIndexColumnDesc, m_cPropSets, m_rgPropSets, &pIndexID));
//Set prop as required using using a value of 1 (not VARIANT_TRUE or VARIANT_FALSE).
FreeProperties(&m_cPropSets, &m_rgPropSets);
SetSettableProperty(DBPROP_INDEX_PRIMARYKEY, DBPROPSET_INDEX, &m_cPropSets, &m_rgPropSets, (void*)1, DBTYPE_BOOL, DBPROPOPTIONS_REQUIRED);
// Try to alter with this prop
TESTC_(AlterIndex(pTableID, pIndexID, &dbidNew), DB_E_ERRORSOCCURRED);
// If the provider doesn't allow setting the prop except to default then we'll get
// NOTSETTABLE here.
if (m_fSetOnlyDefault)
stExpected = DBPROPSTATUS_NOTSETTABLE;
// Verify the prop status based on settability, etc.
TESTC(VerifyPropStatus(m_cPropSets, m_rgPropSets, DBPROP_INDEX_PRIMARYKEY, DBPROPSET_INDEX, stExpected));
CLEANUP:
CleanUpIndex(pTableID, &pIndexID, pIndexColumnDesc, &m_cPropSets, &m_rgPropSets);
ReleaseDBID(&dbidNew, FALSE);
TRETURN
}
// }} TCW_VAR_PROTOTYPE_END
// {{ TCW_VAR_PROTOTYPE(26)
//*-----------------------------------------------------------------------
// @mfunc Set invalid properties OPTIONAL and change name, verify new name does exist
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCProp_SingCol::Variation_26()
{
DBINDEXCOLUMNDESC *pIndexColumnDesc = NULL;
CDBID dbidNew(DBKIND_NAME, MakeObjectName(L"IAlterIn", m_cMaxIndexName));
DBID * pTableID = &(m_pNoNullTable->GetTableIDRef());
DBID * pIndexID = NULL;
DBPROPSTATUS stExpected = DBPROPSTATUS_BADVALUE;
TBEGIN
// Initialize pIndexColumnDesc
SAFE_ALLOC(pIndexColumnDesc, DBINDEXCOLUMNDESC, m_cIndexColumnDesc);
memset(pIndexColumnDesc, 0, (size_t)(sizeof(DBINDEXCOLUMNDESC)*m_cIndexColumnDesc));
// Set the prop to valid value so we can get an alterable index
TESTC_PROVIDER(SetSettableProperty(DBPROP_INDEX_PRIMARYKEY, DBPROPSET_INDEX, &m_cPropSets, &m_rgPropSets, (void*)VARIANT_TRUE, DBTYPE_BOOL, DBPROPOPTIONS_REQUIRED));
TESTC_PROVIDER(S_OK == CreateAlterableIndex(pTableID, NULL, m_cIndexColumnDesc,
pIndexColumnDesc, m_cPropSets, m_rgPropSets, &pIndexID));
//Set prop as optional using using a value of 1 (not VARIANT_TRUE or VARIANT_FALSE).
FreeProperties(&m_cPropSets, &m_rgPropSets);
SetSettableProperty(DBPROP_INDEX_PRIMARYKEY, DBPROPSET_INDEX, &m_cPropSets, &m_rgPropSets, (void*)1, DBTYPE_BOOL, DBPROPOPTIONS_OPTIONAL);
// Try to alter with this prop
TESTC_(AlterIndex(pTableID, pIndexID, &dbidNew), DB_S_ERRORSOCCURRED);
// If the provider doesn't allow setting the prop except to default then we'll get
// NOTSETTABLE here.
if (m_fSetOnlyDefault)
stExpected = DBPROPSTATUS_NOTSETTABLE;
// Verify the prop status based on settability, etc.
TESTC(VerifyPropStatus(m_cPropSets, m_rgPropSets, DBPROP_INDEX_PRIMARYKEY, DBPROPSET_INDEX, stExpected));
CLEANUP:
CleanUpIndex(pTableID, &pIndexID, pIndexColumnDesc, &m_cPropSets, &m_rgPropSets);
ReleaseDBID(&dbidNew, FALSE);
TRETURN
}
// }} TCW_VAR_PROTOTYPE_END
// {{ TCW_TERMINATE_METHOD
//*-----------------------------------------------------------------------
// @mfunc TestCase Termination Routine
//
// @rdesc TEST_PASS or TEST_FAIL
//
BOOL TCProp_SingCol::Terminate()
{
// TO DO: Add your own code here
// {{ TCW_TERM_BASECLASS_CHECK2
return(CAlterIndex::Terminate());
} // }}
// }} TCW_TERMINATE_METHOD_END
// }} TCW_TC_PROTOTYPE_END
// {{ TCW_TC_PROTOTYPE(TCTransact)
//*-----------------------------------------------------------------------
//| Test Case: TCTransact - Commit/abort behavior for AlterIndex
//| Created: 9/22/99
//*-----------------------------------------------------------------------
TCTransact::TCTransact(void)
{
m_pTransact = NULL;
m_ulSupportedTxnDDL = DBPROPVAL_TC_NONE;
m_hrTxn = E_FAIL;
}
//*-----------------------------------------------------------------------
// @mfunc TestCase Initialization Routine
//
// @rdesc TRUE or FALSE
//
BOOL TCTransact::Init()
{
// {{ TCW_INIT_BASECLASS_CHECK
if(CAlterIndex::Init())
// }}
{
// Create a transaction object
m_pTransact = new CTransaction(L"TCTransact");
TESTC(m_pTransact != NULL);
// We have to use a different table here than the
// one we're calling AlterIndex on, otherwise when the transaction
// is opened on the table and AlterIndex is called we'll get
// DB_E_TABLEINUSE. Use our nullable table (m_pTable). This will
// fail with ini file as we really end up with only one table.
TESTC_PROVIDER(!GetModInfo()->GetFileName());
// Initialize transact object
TESTC_PROVIDER(m_pTransact->Init(this, m_pTable));
// Get the provider's TXN support for index changes
GetProperty(DBPROP_SUPPORTEDTXNDDL, DBPROPSET_DATASOURCEINFO,
m_pThisTestModule->m_pIUnknown, &m_ulSupportedTxnDDL);
switch(m_ulSupportedTxnDDL)
{
case DBPROPVAL_TC_NONE:
odtLog << L"\tDBPROP_SUPPORTEDTXNDDL: DBPROPVAL_TC_NONE\n";
// No transaction support, thus starting transaction should fail
m_hrTxn = S_OK;
break;
case DBPROPVAL_TC_DML:
odtLog << L"\tDBPROP_SUPPORTEDTXNDDL: DBPROPVAL_TC_DML\n";
// Only DML support, thus starting altering index should fail
m_hrTxn = XACT_E_XTIONEXISTS;
break;
case DBPROPVAL_TC_DDL_COMMIT:
odtLog << L"\tDBPROP_SUPPORTEDTXNDDL: DBPROPVAL_TC_DDL_COMMIT\n";
// Only DML support but DDL commits transaction, thus starting altering
// index should succeed but the transaction will be committed.
m_hrTxn = S_OK;
break;
case DBPROPVAL_TC_DDL_IGNORE:
odtLog << L"\tDBPROP_SUPPORTEDTXNDDL: DBPROPVAL_TC_DDL_IGNORE\n";
// Only DML support but DDL is ignored, thus starting altering
// index should succeed but the index will not be altered.
m_hrTxn = S_OK;
break;
case DBPROPVAL_TC_DDL_LOCK:
odtLog << L"\tDBPROP_SUPPORTEDTXNDDL: DBPROPVAL_TC_DDL_LOCK\n";
// DDL support but table or index is locked until end of transaction
m_hrTxn = S_OK;
break;
case DBPROPVAL_TC_ALL:
odtLog << L"\tDBPROP_SUPPORTEDTXNDDL: DBPROPVAL_TC_ALL\n";
// DDL support
m_hrTxn = S_OK;
break;
default:
{
TESTC(FALSE);
m_ulSupportedTxnDDL = DBPROPVAL_TC_NONE;
}
}
// See if we can start a transaction and register the interface
if(m_pTransact->RegisterInterface(SESSION_INTERFACE, IID_IAlterIndex))
return TRUE;
else
// No transaction support
return TEST_SKIPPED;
}
CLEANUP:
return FALSE;
}
int TCTransact::TestTxn
(
ETXN eTxn,
BOOL fRetaining,
BOOL fCreateInTxn
)
{
BOOL fSuccess = FALSE;
ULONG index=0;
CDBID dbidNew(DBKIND_NAME, MakeObjectName(L"IAlterIn", m_cMaxIndexName));
DBID * pIndexID = NULL;
DBID * pTableID = &(m_pNoNullTable->GetTableIDRef());
HRESULT hr = E_FAIL;
ULONG cPropSets = 0;
DBPROPSET * prgPropSets = NULL;
DBINDEXCOLUMNDESC *pIndexColumnDesc = NULL;
CHECK_MEMORY(dbidNew.uName.pwszName);
// Initialize pIndexColumnDesc
SAFE_ALLOC(pIndexColumnDesc, DBINDEXCOLUMNDESC, m_cColumnDesc);
memset(pIndexColumnDesc, 0, (size_t)(sizeof(DBINDEXCOLUMNDESC)*m_cColumnDesc));
// Set some index props also as no props were set in base class.
TESTC(m_cPropSets == 0);
SetSettableProperty(DBPROP_INDEX_PRIMARYKEY, DBPROPSET_INDEX, &m_cPropSets, &m_rgPropSets, (void*)VARIANT_TRUE, DBTYPE_BOOL, DBPROPOPTIONS_REQUIRED);
SetSettableProperty(DBPROP_INDEX_NULLCOLLATION, DBPROPSET_INDEX, &m_cPropSets, &m_rgPropSets, (void*)DBPROPVAL_NC_START, VT_I4, DBPROPOPTIONS_REQUIRED);
// Create an index that we can later alter.
if (!fCreateInTxn)
TESTC_PROVIDER(S_OK == CreateAlterableIndex(pTableID, NULL, m_cIndexColumnDesc,
pIndexColumnDesc, m_cPropSets, m_rgPropSets, &pIndexID));
// Set a property to force non-firehose cursor. Note this is a *very*
// provider-specific HACK. Don't check return code as it might not be
// supported. Why do I have to do this? Because:
// 1) StartTransaction opens a rowset.
// 2) AlterIndex helper function opens IDBSchemaRowset.
// 3) Can't create a new connection inside transaction.
// Since the CTransaction object has it's own command I really don't need
// to set the prop back.
SetProperty(DBPROP_IRowsetLocate, DBPROPSET_ROWSET, &cPropSets, &prgPropSets, (void*)VARIANT_TRUE, DBTYPE_BOOL, DBPROPOPTIONS_REQUIRED);
TESTC(m_pTransact->StartTransaction(SELECT_ALLFROMTBL, NULL,
cPropSets, prgPropSets, NULL, ISOLATIONLEVEL_READUNCOMMITTED));
// Create an index that we can later alter.
if (fCreateInTxn)
TESTC_PROVIDER(S_OK == CreateAlterableIndex(pTableID, NULL, m_cIndexColumnDesc,
pIndexColumnDesc, m_cPropSets, m_rgPropSets, &pIndexID));
//Try AlterIndex in the middle of the transaction, expect appropriate result
TESTC_(hr = AlterIndex(pTableID, pIndexID, &dbidNew), m_hrTxn);
// If provider commits transaction when DDL is used we need to start again.
if (m_ulSupportedTxnDDL == DBPROPVAL_TC_DDL_COMMIT)
{
// Are we in a transaction?? Spec is unclear, spec bug opened. Specifically
// what is the fRetaining behavior here.
m_pTransact->CleanUpTransaction(S_OK);
// Start another transaction
TESTC(m_pTransact->StartTransaction(SELECT_ALLFROMTBL, NULL,
0, NULL, NULL, ISOLATIONLEVEL_READUNCOMMITTED));
}
// If provider locks index until end of transaction we should not be able to alter
// again, right? But we need a new session to verify this.
if (m_ulSupportedTxnDDL == DBPROPVAL_TC_DDL_LOCK)
{
CDBID dbidLock(DBKIND_NAME, MakeObjectName(L"IAlterIn", m_cMaxIndexName));
HRESULT hrLock = E_FAIL;
IAlterIndex * pIAlterIndex = m_pIAlterIndex;
IDBCreateSession * pIDBCreateSession = (IDBCreateSession *)m_pThisTestModule->m_pIUnknown;
CHECK_MEMORY(dbidLock.uName.pwszName);
// Get a new session object
TESTC_(pIDBCreateSession->CreateSession(NULL, IID_IAlterIndex, (IUnknown**)&m_pIAlterIndex), S_OK);
// What error do I expect from this??? DB_E_TABLEINUSE seems reasonable
CHECK(hrLock = AlterIndex(pTableID, &dbidNew, &dbidLock), DB_E_TABLEINUSE);
// Release the new sesion object and put the old one back
SAFE_RELEASE(m_pIAlterIndex);
m_pIAlterIndex = pIAlterIndex;
// If it did succeed we need to fix things up
if (SUCCEEDED(hrLock))
{
SAFE_FREE(dbidNew.uName.pwszName);
dbidNew.uName.pwszName = dbidLock.uName.pwszName;
}
}
if (eTxn == ETXN_COMMIT)
{
//Commit the transaction, with retention as specified
TESTC(m_pTransact->GetCommit(fRetaining));
}
else
{
//Abort the transaction, with retention as specified
TESTC(m_pTransact->GetAbort(fRetaining));
}
// If we commited the transaction, then the new name is the right one,
// otherwise it's still the previous one.
if ((eTxn == ETXN_COMMIT || m_ulSupportedTxnDDL == DBPROPVAL_TC_DDL_COMMIT) &&
m_ulSupportedTxnDDL != DBPROPVAL_TC_DDL_IGNORE)
{
// Make sure the new index exists and the props are right.
// Note our helper does this immediately after altering, but the
// commit may have a bug and actually abort, so we need to check
// again.
COMPARE(CheckIndex(pTableID, &dbidNew, m_cPropSets, m_rgPropSets), TRUE);
// Release the old index name
ReleaseDBID(pIndexID, FALSE);
TESTC_(DuplicateDBID(dbidNew, pIndexID), S_OK);
// Create another new index name
SAFE_FREE(dbidNew.uName.pwszName);
dbidNew.uName.pwszName = MakeObjectName(L"IAlterIn", m_cMaxIndexName);
CHECK_MEMORY(dbidNew.uName.pwszName);
}
// Re-commit or re-abort the transaction because CheckIndex ends up starting
// another transaction because CheckIndex2 opens another rowset on the table if
// using integrated indexes.
if (eTxn == ETXN_COMMIT)
{
//Commit the transaction, with retention as specified
TESTC(m_pTransact->GetCommit(fRetaining));
}
else
{
//Abort the transaction, with retention as specified
TESTC(m_pTransact->GetAbort(fRetaining));
}
// If the index creation was aborted
if (fCreateInTxn && eTxn == ETXN_ABORT &&
m_ulSupportedTxnDDL != DBPROPVAL_TC_DDL_COMMIT)
{
BOOL fExists = FALSE;
// The index creation was aborted as well, make sure it doesn't exist
if(S_OK == DoesIndexExist(pTableID,
pIndexID, &fExists))
TESTC(!fExists);
}
else
// The index is available, make sure everything still works after
// commit or abort
TESTC_(hr = AlterIndex(pTableID, pIndexID, &dbidNew), S_OK);
fSuccess = TRUE;
CLEANUP:
//Return code of Commit/Abort will vary depending on whether
//or not we have an open txn, so adjust accordingly
if (fRetaining)
{
BOOL fExists = FALSE;
// We abort the transaction, thus the index will not
// retain the new value.
m_pTransact->CleanUpTransaction(S_OK);
// The new index should not exist after abort
if(S_OK == DoesIndexExist(pTableID,
&dbidNew, &fExists))
COMPARE(fExists, FALSE);
if (!fExists)
// Since the new index doesn't exist dropping should return NOINDEX.
CHECK(m_pIIndexDef->DropIndex(pTableID, &dbidNew), DB_E_NOINDEX);
}
else
{
// We weren't in a transaction on the last AlterIndex,
// thus the index will have the new value. Make it so.
// Release the old index name
ReleaseDBID(pIndexID, FALSE);
CHECK(DuplicateDBID(dbidNew, pIndexID), S_OK);
m_pTransact->CleanUpTransaction(XACT_E_NOTRANSACTION);
}
// Drop the altered index, otherwise we may end up with dupicate PrimaryKey index
// which is not allowed.
CleanUpIndex(pTableID, &pIndexID, pIndexColumnDesc, &m_cPropSets, &m_rgPropSets);
ReleaseDBID(&dbidNew, FALSE);
FreeProperties(&cPropSets, &prgPropSets);
return fSuccess;
}
// {{ TCW_VAR_PROTOTYPE(1)
//*-----------------------------------------------------------------------
// @mfunc Commit Retaining
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCTransact::Variation_1()
{
return TestTxn(ETXN_COMMIT, TRUE);
}
// }} TCW_VAR_PROTOTYPE_END
// {{ TCW_VAR_PROTOTYPE(2)
//*-----------------------------------------------------------------------
// @mfunc Commit Non Retaining
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCTransact::Variation_2()
{
return TestTxn(ETXN_COMMIT, FALSE);
}
// }} TCW_VAR_PROTOTYPE_END
// {{ TCW_VAR_PROTOTYPE(3)
//*-----------------------------------------------------------------------
// @mfunc Abort Retaining
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCTransact::Variation_3()
{
return TestTxn(ETXN_ABORT, TRUE);
}
// }} TCW_VAR_PROTOTYPE_END
// {{ TCW_VAR_PROTOTYPE(4)
//*-----------------------------------------------------------------------
// @mfunc Abort Non Retaining
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCTransact::Variation_4()
{
return TestTxn(ETXN_ABORT, FALSE);
}
// }} TCW_VAR_PROTOTYPE_END
// {{ TCW_VAR_PROTOTYPE(5)
//*-----------------------------------------------------------------------
// @mfunc Commit Retaining, create index in txn
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCTransact::Variation_5()
{
return TestTxn(ETXN_COMMIT, TRUE, TRUE);
}
// }} TCW_VAR_PROTOTYPE_END
// {{ TCW_VAR_PROTOTYPE(6)
//*-----------------------------------------------------------------------
// @mfunc Commit Non Retaining, create index in txn
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCTransact::Variation_6()
{
return TestTxn(ETXN_COMMIT, FALSE, TRUE);
}
// }} TCW_VAR_PROTOTYPE_END
// {{ TCW_VAR_PROTOTYPE(7)
//*-----------------------------------------------------------------------
// @mfunc Abort Retaining, create index in txn
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCTransact::Variation_7()
{
return TestTxn(ETXN_ABORT, TRUE, TRUE);
}
// }} TCW_VAR_PROTOTYPE_END
// {{ TCW_VAR_PROTOTYPE(8)
//*-----------------------------------------------------------------------
// @mfunc Abort Non Retaining, create index in txn
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCTransact::Variation_8()
{
return TestTxn(ETXN_ABORT, FALSE, TRUE);
}
// }} TCW_VAR_PROTOTYPE_END
// {{ TCW_TERMINATE_METHOD
//*-----------------------------------------------------------------------
// @mfunc TestCase Termination Routine
//
// @rdesc TEST_PASS or TEST_FAIL
//
BOOL TCTransact::Terminate()
{
SAFE_DELETE(m_pTransact);
// {{ TCW_TERM_BASECLASS_CHECK2
return(CAlterIndex::Terminate());
} // }}
// }} TCW_TERMINATE_METHOD_END
// }} TCW_TC_PROTOTYPE_END