//-------------------------------------------------------------------- // Microsoft OLE DB Test // // Copyright 1995-2000 Microsoft Corporation. // // @doc // // @module IRowIden.cpp | Source file for test module IRowsetIdentity. // #include "modstandard.hpp" #define DBINITCONSTANTS // Must be defined to initialize constants in OLEDB.H #define INITGUID #include "IRowIden.h" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Module Values // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // {{ TCW_MODULE_GLOBALS DECLARE_MODULE_CLSID = { 0x20ac17d1, 0xf171, 0x11cf, { 0x89, 0xc2, 0x00, 0xaa, 0x00, 0xb5, 0xa9, 0x1b }}; DECLARE_MODULE_NAME("IRowsetIdentity"); DECLARE_MODULE_OWNER("Microsoft"); DECLARE_MODULE_DESCRIP("The test module for IRowsetIdentity"); DECLARE_MODULE_VERSION(836168420); // }} // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Globals - - - - - - - - - - - - - - - - - - #define g_MSDASQL (m_pThisTestModule->m_ProviderClsid == CLSID_MSDASQL) // - - - - - - - - - - - - - - - - - - CTable *g_pCTable = NULL; //pointer to the global table IDBCreateSession *g_pIDBCreateSession= NULL; //pointer to IDBCreateSession interface IDBCreateCommand *g_pIDBCreateCommand= NULL; //pointer to IDBCreateComand interface IOpenRowset *g_pIOpenRowset = NULL; //pointer to IOpenRowset interface DB_LORDINAL *g_rgTableColOrds; //Array of col ordinals for table. DBORDINAL g_cRowsetCols; //Count of columns in rowset. DBCOUNTITEM g_ulRowCount; //Flag whether the provider is readonly BOOL g_fReadOnlyProvider; BOOL g_fTestValid; //Flag whether the props are Settable or TRUE BOOL g_fIRowsetChange; BOOL g_fCommands; BOOL g_fIRowsetLocate; BOOL g_fROWSETUPDATABLE; BOOL g_fUPDATEPENDING; BOOL g_fFETCHBACKWARDS; BOOL g_fLOCATE; BOOL g_fIDBSchemaRowset; BOOL g_fLITERALIDENITIY; BOOL g_fSTRONGIDENTITY; BOOL g_fREMOVEDELETED; BOOL g_fRETURNPENDINGINSERTS; BOOL g_fOWNUPDATEDELETE; BOOL g_fOWNINSERT; DBCOUNTITEM g_ulNextRow; //PendingDeletes //0 - OWNUPDATEDELETE - T LITERALIDENTITY - T REMOVEDELETED - T Deleted Row Removed //1 - OWNUPDATEDELETE - T LITERALIDENTITY - T REMOVEDELETED - F Deleted Row Present //2 - OWNUPDATEDELETE - T LITERALIDENTITY - F REMOVEDELETED - F Deleted Row Present //3 - OWNUPDATEDELETE - T LITERALIDENTITY - F REMOVEDELETED - T Deleted Row Present //4 - OWNUPDATEDELETE - F LITERALIDENTITY - T REMOVEDELETED - T No Change to Rowset Visible //5 - OWNUPDATEDELETE - F LITERALIDENTITY - T REMOVEDELETED - F No Change to Rowset Visible //6 - OWNUPDATEDELETE - F LITERALIDENTITY - F REMOVEDELETED - F No Change to Rowset Visible //7 - OWNUPDATEDELETE - F LITERALIDENTITY - F REMOVEDELETED - T No Change to Rowset Visible //PendingInserts //0 - OWNINSERT - T LITERALIDENTITY - T RETURNPENDINGINSERTS - T Inserted Row Present //1 - OWNINSERT - T LITERALIDENTITY - T RETURNPENDINGINSERTS - F Inserted Row not Seen //2 - OWNINSERT - T LITERALIDENTITY - F RETURNPENDINGINSERTS - F Inserted Row not Seen //3 - OWNINSERT - T LITERALIDENTITY - F RETURNPENDINGINSERTS - T Inserted Row not Seen //4 - OWNINSERT - F LITERALIDENTITY - T RETURNPENDINGINSERTS - T No Change to Rowset Visible //5 - OWNINSERT - F LITERALIDENTITY - T RETURNPENDINGINSERTS - F No Change to Rowset Visible //6 - OWNINSERT - F LITERALIDENTITY - F RETURNPENDINGINSERTS - F No Change to Rowset Visible //7 - OWNINSERT - F LITERALIDENTITY - F RETURNPENDINGINSERTS - T No Change to Rowset Visible //PendingUpdates(static) //0 - OWNUPDATEDELETE - T LITERALIDENTITY - T row handle held Change is Seen //1 - OWNUPDATEDELETE - T LITERALIDENTITY - T row handle not held Change is Seen //2 - OWNUPDATEDELETE - T LITERALIDENTITY - F row handle not held Change is Seen //3 - OWNUPDATEDELETE - T LITERALIDENTITY - F row handle held Change is Seen //4 - OWNUPDATEDELETE - F LITERALIDENTITY - T row handle held Change is Seen //5 - OWNUPDATEDELETE - F LITERALIDENTITY - T row handle not held Change is Not Seen //6 - OWNUPDATEDELETE - F LITERALIDENTITY - F row handle not held Change is Not Seen //7 - OWNUPDATEDELETE - F LITERALIDENTITY - F row handle held Change is Not Seen //PendingUpdates(key) //follow rules for Inserts and Deletes enum ePrptIdx { IDX_LiteralIdentity=0, IDX_StrongIdentity, IDX_FetchBackwards, IDX_ScrollBackwards, IDX_CanHoldRows, IDX_RemoveDeleted, IDX_OwnUpdateDelete, IDX_OwnInsert, IDX_OtherUpdateDelete, IDX_OtherInsert, IDX_IRowsetIdentity, IDX_IRowsetUpdate, IDX_IRowsetLocate, IDX_IRowsetChange }; const ULONG g_PROPERTY_COUNT = IDX_IRowsetChange+1; const WORD g_wePrptIdxFIRST = IDX_LiteralIdentity; const WORD g_wePrptIdxLAST = IDX_IRowsetChange; //record the properties default values struct DBPrptRecord { DBPROPID dwPropID; BOOL fSupported; VARIANT_BOOL fDefault; DBPROPFLAGS dwFlags; }g_rgDBPrpt[g_PROPERTY_COUNT]; //-------------------------------------------------------------------- // @func Print out message on the screen that a particular property // is not supported. //-------------------------------------------------------------------- BOOL PrintNotSupported(ULONG cProperties) { BOOL fPass=TRUE; switch(cProperties) { case IDX_LiteralIdentity: odtLog<m_pIUnknown2); //Todo: check if provider supports IRowsetUpdatable or ICommand //TRUE if interface COULD be supported if (IsReqInterface(ROWSET_INTERFACE,IID_IRowsetChange) || !(GetModInfo()->IsStrictLeveling())) { g_fIRowsetChange = TRUE; } if (IsReqInterface(COMMAND_INTERFACE,IID_ICommand) || !(GetModInfo()->IsStrictLeveling())) { g_fCommands = TRUE; } if (IsReqInterface(COMMAND_INTERFACE,IID_IRowsetLocate) || !(GetModInfo()->IsStrictLeveling())) { g_fIRowsetLocate = TRUE; } pwszProviderName = GetProviderName(pThisTestModule->m_pIUnknown2); //IDBCreateSession if(!VerifyInterface(pThisTestModule->m_pIUnknown, IID_IDBCreateSession, DATASOURCE_INTERFACE, (IUnknown**)&g_pIDBCreateSession)) return FALSE; //IDBCreateCommand if(!VerifyInterface(pThisTestModule->m_pIUnknown2, IID_IDBCreateCommand, SESSION_INTERFACE, (IUnknown**)&g_pIDBCreateCommand)) { odtLog << L"IDBCreateCommand is not supported by Provider." << ENDL; } //IOpenRowset if(!VerifyInterface(pThisTestModule->m_pIUnknown2, IID_IOpenRowset, SESSION_INTERFACE, (IUnknown**)&g_pIOpenRowset)) { odtLog << L"IOpenRowset is not supported by Provider." << ENDL; } //IOpenRowset if(!VerifyInterface(g_pIOpenRowset, IID_IDBSchemaRowset, SESSION_INTERFACE, (IUnknown**)&pIDBSchemaRowset)) { odtLog << L"IDBSchemaRowset is not supported by Provider." << ENDL; } else { g_fIDBSchemaRowset = TRUE; } //limit the number of rows in the table for weak providers that can't handle //but just a little bit of rows if (g_fReadOnlyProvider) { cNumTableRows = 9; } else { cNumTableRows = TABLE_ROW_COUNT; } //create the table g_pCTable = new CTable ( pThisTestModule->m_pIUnknown2, (WCHAR *)gwszModuleName, USENULLS ); if(!g_pCTable || !SUCCEEDED(g_pCTable->CreateTable(cNumTableRows,1,NULL,PRIMARY,TRUE))) { if(g_pCTable) { g_pCTable->DropTable(); delete g_pCTable; g_pCTable=NULL; } odtLog<CreateRowset( USE_OPENROWSET, IID_IRowsetIdentity, cPropSets, rgPropSets, (IUnknown**)&pIRowset, NULL, &g_cRowsetCols, &g_rgTableColOrds ); //if E_NOINTERFACE is returned, IRowsetIdentity is not supported by the provider if(hr==ResultFromScode(E_NOINTERFACE)) { odtLog<GetPropertyInfo ( 1, &DBPropIDSet, &cPropertyInfoSets, &prgPropertyInfoSets, &ppDescBuffer ); //should get info on all props if ((*prgPropertyInfoSets).cPropertyInfos!=g_PROPERTY_COUNT) { goto CLEANUP; } //record the property info for(cPropertiesIndex=g_wePrptIdxFIRST;cPropertiesIndex<=g_wePrptIdxLAST;cPropertiesIndex++) { g_rgDBPrpt[cPropertiesIndex].dwFlags= prgPropertyInfoSets[0].rgPropertyInfos[cPropertiesIndex].dwFlags; } //get property info on the rowset if(!VerifyInterface(pIRowset, IID_IRowsetInfo, ROWSET_INTERFACE, (IUnknown**)&pIRowsetInfo)) { goto CLEANUP; } //Get Property values hr=pIRowsetInfo->GetProperties(1,&DBPropIDSet, &cProperties, &prgProperties); //should get info on all props if ((*prgProperties).cProperties!=g_PROPERTY_COUNT) { goto CLEANUP; } //mark the properties for(cPropertiesIndex=g_wePrptIdxFIRST;cPropertiesIndex<=g_wePrptIdxLAST;cPropertiesIndex++) { //mark the not supported properties if(prgProperties[0].rgProperties[cPropertiesIndex].dwStatus==DBPROPSTATUS_NOTSUPPORTED) { g_rgDBPrpt[cPropertiesIndex].fSupported =FALSE; g_rgDBPrpt[cPropertiesIndex].fDefault =FALSE; PrintNotSupported(cPropertiesIndex); } else { if(prgProperties[0].rgProperties[cPropertiesIndex].dwStatus!=DBPROPSTATUS_OK) { odtLog<GetFileName() && g_pCTable) { //delete all rows in the table. if(!CHECK(g_pCTable->DeleteRows(ALLROWS),S_OK)) return FALSE; // Regenerate the rowset if(!CHECK(g_pCTable->Insert(PRIMARY, 1, g_ulRowCount),S_OK)) return FALSE; } //drop tables if(g_pCTable) { g_pCTable->DropTable(); delete g_pCTable; } SAFE_RELEASE(g_pIDBCreateSession); SAFE_RELEASE(g_pIDBCreateCommand); SAFE_RELEASE(g_pIOpenRowset); PROVIDER_FREE(g_rgTableColOrds); //Release IDBCreateCommand interface return (ModuleReleaseDBSession(pThisTestModule)); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Base Test Case Section // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // // TCIRowsetIdentity: the base class for the rest of test cases in this // test module. // // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - class TCIRowsetIdentity : public CRowsetObject { private: protected: //@cmember: interface pointer for IRowsetIdentity IRowsetIdentity *m_pIRowsetIdentity; //@cmember: interface pointer for IRowsetChange IRowsetChange *m_pIRowsetChange; //@cmember: interface pointer for IRowsetUpdate IRowsetUpdate *m_pIRowsetUpdate; //@cmember: interface pointer for IRowsetLocate IRowsetLocate *m_pIRowsetLocate; //@cmember: interface pointer for IRowset IRowset *m_pIRowset; //@cmember: interface pointer for IRowset IDBSchemaRowset *m_pIDBSchemaRowset; //@cmember: accessory handle HACCESSOR m_hAccessor; //@cmember: the size of a row DBLENGTH m_cRowSize; //@cmember: the count of binding structure DBCOUNTITEM m_cBinding; //@cmember: the array of binding strucuTRUE DBBINDING *m_rgBinding; //@cmember: the column information DBCOLUMNINFO *m_rgInfo; //@cmember: the string buffer to hold the name WCHAR *m_pStringsBuffer; //@cmember: the pointer to the row buffer void *m_pData; //@cmember: the location of accessor handle EACCESSORLOCATION m_eAccessorLocation; //@cmember: The Updatability Flags for DBPROP_UPDATABILITY ULONG m_ulUpdFlags; //@mfunc: initialialize interface pointers BOOL Init(); //@mfunc: Terminate BOOL Terminate(); //@mfunc: Create a command object and set properties, execute a sql statement, // and create a rowset object. Create an accessor on the rowset BOOL GetRowsetAndAccessor ( EQUERY eSQLStmt, ULONG cProperties=0, const DBPROPID *rgProperties=NULL, ULONG cPropertiesUnset=0, const DBPROPID *rgPropertiesUnset=NULL, EACCESSORLOCATION eAccessorLocation=NO_ACCESSOR, DBACCESSORFLAGS dwAccessorFlags=DBACCESSOR_ROWDATA, DBPART dwPart=DBPART_VALUE|DBPART_STATUS|DBPART_LENGTH, ECOLS_BOUND eColsToBind=ALL_COLS_BOUND, ECOLUMNORDER eBindingOrder=FORWARD, ECOLS_BY_REF eColsByRef=NO_COLS_BY_REF, DBTYPE dbTypeModifier=DBTYPE_EMPTY, DBORDINAL cColsToBind=0, ULONG_PTR *rgColsToBind=NULL ); //@mfun: create an accessor on the rowset. BOOL GetAccessorOnRowset ( EACCESSORLOCATION eAccessorLocation=ON_ROWSET_ACCESSOR, DBACCESSORFLAGS dwAccessorFlags=DBACCESSOR_ROWDATA, DBPART dwPart=DBPART_VALUE|DBPART_STATUS|DBPART_LENGTH, ECOLS_BOUND eColsToBind=UPDATEABLE_COLS_BOUND, ECOLUMNORDER eBindingOrder=FORWARD, ECOLS_BY_REF eColsByRef=NO_COLS_BY_REF, DBTYPE dbTypeModifier=DBTYPE_EMPTY, DBORDINAL cColsToBind=0, ULONG_PTR *rgColsToBind=NULL ); BOOL CheckExpectedData ( HROW hRow, void *pExpectedData, BOOL fSetData ); HRESULT InsertOneRow ( DBCOUNTITEM cRowNumber, HROW *pHRow ); HRESULT ChangeOneRow ( HROW hRow, DBCOUNTITEM cRowNumber, void **ppData=NULL ); HRESULT DeleteRows ( DBCOUNTITEM cRows, HROW *pHRow ); HRESULT UpdateRows ( DBCOUNTITEM cRows, HROW *pHRow, DBROWSTATUS **ppDBRowStatus=NULL ); HRESULT UndoRows ( DBCOUNTITEM cRows, HROW *pHRow ); HRESULT ReleaseRows ( DBCOUNTITEM cRows, HROW **ppHRow, BOOL fFreeMemory ); //@mfun: Get the bookmark for the row BOOL GetBookmark ( DBCOUNTITEM ulRow, DBBKMARK *pcbBookmark, BYTE **ppBookmark ); BOOL GetBookmarkByRow ( HROW hRow, DBBKMARK *pcbBookmark, BYTE **ppBookmark ); //@mfunc: Get cursor type of the rowset ECURSOR GetCursorType(); //@mfunc: Return TRUE is we are on QueryBased Update mode BOOL QueryBasedUpdate(); //return BOOL Prop value BOOL GetBoolPropValForRowset(DBPROPID eProp); //@mfunc: Return HRESULT from IsSameRows atfer it is check according to bocoo props HRESULT IsSameRowAccoringToProps( HROW *pHRowThis, HROW *pHRowThat ); //@mfunc: Get the Updatable columns that is not part of the key BOOL GetNonKeyAndUpdatable( DBORDINAL *pcbCol, DBORDINAL **prgColNum, IMalloc *pIMalloc); //@mfunc: Compare the data from 2 row handles BOOL CheckRowsByData ( HROW hThisRow, HROW hThatRow, ULONG cSize, IRowset *pIRowset, HACCESSOR hAccessor ); //@mfunc: release the accessor on the rowset void ReleaseAccessorOnRowset(); //@mfunc: release a rowset object and accessor created on it void ReleaseRowsetAndAccessor(); public: //constructor TCIRowsetIdentity(WCHAR * wstrTestCaseName) //Takes TestCase Class name as parameter : CRowsetObject(wstrTestCaseName) { m_pIRowsetIdentity = NULL; m_pIRowsetChange = NULL; m_pIRowsetUpdate = NULL; m_pIRowsetLocate = NULL; m_pStringsBuffer = NULL; m_pIRowset = NULL; m_pIDBSchemaRowset = NULL; m_hAccessor = NULL; m_cRowSize = 0; m_cBinding = 0; m_rgBinding = NULL; m_rgInfo = NULL; m_pData = NULL; m_eAccessorLocation = NO_ACCESSOR; m_ulUpdFlags = DBPROPVAL_UP_CHANGE|DBPROPVAL_UP_DELETE|DBPROPVAL_UP_INSERT; } //destructor virtual ~TCIRowsetIdentity(){}; //check Properties BOOL IsPropertySet(GUID propset, DBPROPID propid, IUnknown * pIUnknown, LONG lValue); }; //-------------------------------------------------------------------- //@mfunc: Init creates a Data Source object, a DB Session object, //and a command object and initialize corresponding interface pointers. // //-------------------------------------------------------------------- BOOL TCIRowsetIdentity::Init() { if(!CRowsetObject::Init()) return FALSE; //if the test is using an ini file and if this test is allowed to use commands //and IRowsetChange (checked here from init string, not properties) and IRowsetChange is supported if( GetModInfo()->GetFileName() && g_fIRowsetChange && g_rgDBPrpt[IDX_IRowsetChange].fSupported) { //delete all rows in the table. if(!CHECK(g_pCTable->DeleteRows(ALLROWS),S_OK)) return FALSE; // Regenerate the rowset if(!CHECK(g_pCTable->Insert(PRIMARY, 1, g_ulRowCount),S_OK)) return FALSE; } else if(g_fIRowsetChange&&g_fCommands) { //drop the table and create an empty one if(!CHECK(g_pCTable->DropTable(),S_OK)) { return FALSE; } if(!SUCCEEDED(g_pCTable->CreateTable(g_ulRowCount,1,NULL,PRIMARY,TRUE))) { return FALSE; } } //Indicate NextRow in table g_ulNextRow = g_pCTable->GetRowsOnCTable() + 10; //set the DBSession. No need to create a DB Session everytime SetDBSession(g_pIOpenRowset); //set the table. No need to create a table everytime. SetTable(g_pCTable,DELETETABLE_NO); return TRUE; } //-------------------------------------------------------------------- //@mfunc: Terminate release the data source object, DB Session object, Command object // //-------------------------------------------------------------------- BOOL TCIRowsetIdentity::Terminate() { //Release the existing Session ReleaseDBSession(); return (CRowsetObject::Terminate()); } //-------------------------------------------------------------------- //@mfunc: Compare the row handles byte by byte //-------------------------------------------------------------------- BOOL CompareHandlesByLiteral ( HROW hThisRow, HROW hThatRow, BOOL fNewlyInserted, BOOL fExpected ) { BOOL fResult; //if DBPROP_LITERLIDENTITY is not supported or is VARIANT_FALSE. //Return TEST_SKIPPED if (!g_fLITERALIDENITIY) { return TRUE; } //if DBPROP_STRONGIDENITY is not supported or is VARIANT_FALSE AND the rows are newly //inserted, return TEST_SKIPPED if ((!g_fSTRONGIDENTITY) && fNewlyInserted) { return TRUE; } //otherwise, compare the row handles bit by bit if(memcmp(&hThisRow, &hThatRow, sizeof(HROW))) { fResult = FALSE; } else { fResult = TRUE; } if(fResult==fExpected) { return TRUE; } else { return FALSE; } } //-------------------------------------------------------------------- //@mfunc: Compare the data from 2 row handles //-------------------------------------------------------------------- BOOL CheckRowsByData ( HROW hThisRow, HROW hThatRow, ULONG cSize, IRowset *pIRowset, HACCESSOR hAccessor ) { BOOL fResult = FALSE; void *pData1 = NULL; void *pData2 = NULL; //alloc 2 buffers if ( !(pData1=PROVIDER_ALLOC(cSize)) || !(pData2=PROVIDER_ALLOC(cSize)) ) { goto END; } //fill the 2 buffers from the two different row handles if(!CHECK(pIRowset->GetData(hThisRow, hAccessor, pData1),S_OK)) { goto END; } if(!CHECK(pIRowset->GetData(hThatRow, hAccessor, pData2),S_OK)) { goto END; } //return TRUE if the data from the row handles are the same if(!memcmp(pData1, pData2, cSize)) { fResult = TRUE; } else { fResult = FALSE; } END: PROVIDER_FREE(pData1); PROVIDER_FREE(pData2); return fResult; } //-------------------------------------------------------------------- //@mfunc: Create a command object and set properties, execute a sql statement, // and create a rowset object. Create an accessor on the rowset // //-------------------------------------------------------------------- BOOL TCIRowsetIdentity::GetRowsetAndAccessor ( EQUERY eSQLStmt, //the SQL Statement to create ULONG cProperties, //the count of properties const DBPROPID *rgProperties, //the array of properties to be set ULONG cPropertiesUnset, //the count of properties to be unset const DBPROPID *rgPropertiesUnset, //the array of properties to be unset EACCESSORLOCATION eAccessorLocation, //where the accessor should be created DBACCESSORFLAGS dwAccessorFlags, //the accessor flags DBPART dwPart, //the type of binding ECOLS_BOUND eColsToBind, //the columns in accessor ECOLUMNORDER eBindingOrder, //the order to bind columns ECOLS_BY_REF eColsByRef, //which columns to bind by reference DBTYPE dbTypeModifier, //the type modifier used for accessor DBORDINAL cColsToBind, //the count of columns to bind ULONG_PTR *rgColsToBind //the array of column ordinals to bind ) { IColumnsInfo *pIColumnsInfo = NULL; DBCOUNTITEM cRowsObtained = 0; HROW *pHRow = NULL; ULONG cDBPropSet = 1; DBPROPSET rgDBPropSet[2]; DBPROP DBProp; ULONG cDBPropCount = 0; DBORDINAL cCnt = 0; ULONG cCount = 0; HRESULT hr; BOOL fPass = FALSE; WORD i = 0; WORD j = 0; BOOL fNotSupported = FALSE; rgDBPropSet[0].rgProperties = NULL; rgDBPropSet[1].rgProperties = NULL; g_fTestValid = TRUE; //loop throuh all the requested properties for the rowset for (j=0;jCreateRowset ( USE_OPENROWSET, IID_IRowset, cDBPropSet, rgDBPropSet, (IUnknown**)&m_pIRowset, NULL, &g_cRowsetCols, &g_rgTableColOrds ); if (!m_pIRowset) { goto END; } // Check HRESULT if( hr != S_OK ) { // Check for HRESULT returned by SetProperties if( hr == DB_S_ERRORSOCCURRED ) { odtLog<rgProperties[i].dwStatus != DBPROPSTATUS_OK ) { odtLog<GetColumnInfo(&m_cRowsetCols,&m_rgInfo, &m_pStringsBuffer),S_OK)) { goto END; } //remember where the accessor handle is created m_eAccessorLocation=eAccessorLocation; //if eAccessorLocation is NO_ACCESSOR, no need to create an accessor if(eAccessorLocation==NO_ACCESSOR) { fPass=TRUE; goto END; } switch(eAccessorLocation) { case ON_COMMAND_ACCESSOR: //can not create an accessor on the command object if the //the rowset is a simple rowset. //the accessor is created before the rowset is open if(eSQLStmt==USE_OPENROWSET) goto END; break; case ON_ROWSET_FETCH_ACCESSOR: //can not create an accessor after the first fetch if no IRowset //is present on the rowset if(!m_pIRowset) goto END; if(!CHECK(m_pIRowset->GetNextRows(NULL,2,1,&cRowsObtained, &pHRow), S_OK)) goto END; case ON_ROWSET_ACCESSOR: //can not create an accessor on a rowset if no IRowset is present if(!m_pIRowset) goto END; //create an accessor on the rowset if(!CHECK(GetAccessorAndBindings(m_pIAccessor,dwAccessorFlags,&m_hAccessor, &m_rgBinding,&m_cBinding,&m_cRowSize,dwPart,eColsToBind,eBindingOrder, eColsByRef,NULL,&cCnt,NULL,dbTypeModifier,cColsToBind,(LONG_PTR *)rgColsToBind),S_OK)) goto END; break; default: return FALSE; } //make sure cCnt should be the same as m_cRowsetCols if(!COMPARE(cCnt, m_cRowsetCols)) goto END; //allocate memory for the row m_pData=PROVIDER_ALLOC(m_cRowSize); if(m_pData) fPass=TRUE; END: if(rgDBPropSet[0].rgProperties) PROVIDER_FREE(rgDBPropSet[0].rgProperties); SAFE_RELEASE(pIColumnsInfo); if(pHRow) { CHECK(m_pIRowset->ReleaseRows(cRowsObtained,pHRow,NULL,NULL,NULL),S_OK); PROVIDER_FREE(pHRow); //restart position. The rowset returns to its original state CHECK(m_pIRowset->RestartPosition(NULL),S_OK); } return fPass; } //-------------------------------------------------------------------- //@mfunc: Create an accessor on the rowset // //-------------------------------------------------------------------- BOOL TCIRowsetIdentity::GetAccessorOnRowset ( EACCESSORLOCATION eAccessorLocation, //where the accessor should be created DBACCESSORFLAGS dwAccessorFlags, //the accessor flags DBPART dwPart, //the type of binding ECOLS_BOUND eColsToBind, //the columns in accessor ECOLUMNORDER eBindingOrder, //the order to bind columns ECOLS_BY_REF eColsByRef, //which columns to bind by reference DBTYPE dbTypeModifier, //the type modifier used for accessor DBORDINAL cColsToBind, //the count of columns to bind ULONG_PTR *rgColsToBind //the array of column ordinals to bind ) { IUnknown *pIUnknown = NULL; DBCOUNTITEM cRowsObtained = 0; HROW *pHRow = NULL; DBORDINAL cCnt = 0; BOOL fPass = FALSE; //remember where the accessor handle is created m_eAccessorLocation=eAccessorLocation; //eAccessorLocation can not be NO_ACCESSOR if(!COMPARE(eAccessorLocation!=NO_ACCESSOR,TRUE)) { fPass=FALSE; goto END; } switch(eAccessorLocation) { case ON_ROWSET_FETCH_ACCESSOR: //can not create an accessor after the first fetch if no IRowset //is present on the rowset if(!m_pIRowset) goto END; if(!CHECK(m_pIRowset->GetNextRows(NULL,2,1,&cRowsObtained, &pHRow), S_OK)) goto END; pIUnknown=m_pIAccessor; break; case ON_ROWSET_ACCESSOR: //can not create an accessor on a rowset if no IRowset is present if(!m_pIRowset) goto END; pIUnknown=m_pIAccessor; break; case ON_COMMAND_ACCESSOR: default: return FALSE; } //create an accessor on the rowset if(!CHECK(GetAccessorAndBindings( pIUnknown, dwAccessorFlags, &m_hAccessor, &m_rgBinding, &m_cBinding, &m_cRowSize, dwPart, eColsToBind, eBindingOrder, eColsByRef, NULL, &cCnt, NULL, dbTypeModifier, cColsToBind, (LONG_PTR *) rgColsToBind), S_OK )) { goto END; } //make sure cCnt should be the same as m_cRowsetCols if(!COMPARE(cCnt, m_cRowsetCols)) goto END; //allocate memory for the row m_pData=PROVIDER_ALLOC(m_cRowSize); if(m_pData) fPass=TRUE; END: if(pHRow) { CHECK(m_pIRowset->ReleaseRows(cRowsObtained,pHRow,NULL,NULL,NULL),S_OK); PROVIDER_FREE(pHRow); //restart position. The rowset returns to its original state CHECK(m_pIRowset->RestartPosition(NULL),S_OK); } return fPass; } //-------------------------------------------------------------------- // Make sure GetData on the row handle is what to be expected //-------------------------------------------------------------------- BOOL TCIRowsetIdentity::CheckExpectedData ( HROW hRow, void *pExpectedData, BOOL fSetData ) { void *pData = NULL; BOOL fResult = FALSE; if(!(pData=PROVIDER_ALLOC(m_cRowSize))) goto END; //get data one the row handle if(!CHECK(m_pIRowset->GetData(hRow, m_hAccessor, pData),S_OK)) goto END; //compare the buffer fResult=CompareBuffer(pData, pExpectedData, m_cBinding,m_rgBinding, m_pIMalloc, fSetData, FALSE,COMPARE_ONLY); END: if(pData) ReleaseInputBindingsMemory(m_cBinding, m_rgBinding,(BYTE *)pData,TRUE); return fResult; } //-------------------------------------------------------------------- // Insert a new row based on the row number. Return the row handle // and hAccessor //-------------------------------------------------------------------- HRESULT TCIRowsetIdentity::InsertOneRow ( DBCOUNTITEM cRowNumber, HROW *pHRow ) { void *pData = NULL; HRESULT hr = S_OK; if(!pHRow) return E_FAIL; //get data to insert if(!CHECK(FillInputBindings( m_pTable, DBACCESSOR_ROWDATA, m_cBinding, m_rgBinding, (BYTE **)&pData, cRowNumber, g_cRowsetCols, g_rgTableColOrds, PRIMARY),S_OK)) return E_FAIL; //insert hr=m_pIRowsetChange->InsertRow(NULL,m_hAccessor,pData,pHRow); ReleaseInputBindingsMemory(m_cBinding, m_rgBinding,(BYTE *)pData,TRUE); return hr; } //-------------------------------------------------------------------- // Insert a new row based on the row number. Return the row handle // and hAccessor //-------------------------------------------------------------------- HRESULT TCIRowsetIdentity::ChangeOneRow ( HROW hRow, DBCOUNTITEM cRowNumber, void **ppData ) { void *pData = NULL; HRESULT hr = S_OK; //get data to insert if(!CHECK(FillInputBindings(m_pTable, DBACCESSOR_ROWDATA,m_cBinding,m_rgBinding, (BYTE **)&pData,cRowNumber,g_cRowsetCols,g_rgTableColOrds,PRIMARY),S_OK)) return E_FAIL; //change hr=m_pIRowsetChange->SetData(hRow,m_hAccessor,pData); if(ppData) *ppData=pData; else ReleaseInputBindingsMemory(m_cBinding, m_rgBinding,(BYTE *)pData,TRUE); return hr; } //-------------------------------------------------------------------- // Delete the rows //-------------------------------------------------------------------- HRESULT TCIRowsetIdentity::DeleteRows ( DBCOUNTITEM cRows, HROW *pHRow ) { if(!m_pIRowsetChange) return E_FAIL; return (m_pIRowsetChange->DeleteRows(NULL,cRows, pHRow,NULL)); } //-------------------------------------------------------------------- // Update the rows //-------------------------------------------------------------------- HRESULT TCIRowsetIdentity::UpdateRows ( DBCOUNTITEM cRows, HROW *pHRow, DBROWSTATUS **ppDBRowStatus ) { DBCOUNTITEM cRowsUpdated = 0; HROW *pHRowUpdated = NULL; HRESULT hr = E_FAIL; if(!m_pIRowsetUpdate) return E_FAIL; hr = m_pIRowsetUpdate->Update(NULL, cRows, pHRow,&cRowsUpdated, &pHRowUpdated, ppDBRowStatus); PROVIDER_FREE(pHRowUpdated); return hr; } //-------------------------------------------------------------------- // Undo the rows //-------------------------------------------------------------------- HRESULT TCIRowsetIdentity::UndoRows ( DBCOUNTITEM cRows, HROW *pHRow ) { if(!m_pIRowsetUpdate) return E_FAIL; return (m_pIRowsetUpdate->Undo(NULL,cRows, pHRow,NULL,NULL,NULL)); } //-------------------------------------------------------------------- // Release the row handles. Free the memory if asked //-------------------------------------------------------------------- HRESULT TCIRowsetIdentity::ReleaseRows ( DBCOUNTITEM cRows, HROW **ppHRow, BOOL fFreeMemory ) { HRESULT hr; hr=m_pIRowset->ReleaseRows(cRows, *ppHRow, NULL,NULL, NULL); if(fFreeMemory) { PROVIDER_FREE(*ppHRow); *ppHRow=NULL; } return hr; } //-------------------------------------------------------------------- //@mfun: Get the bookmark for the row. The function has to be called // after the GetRowsetAndAccessor that creates an accessor on the // rowset. The accessor as to binds the 0th column on the rowset. // //-------------------------------------------------------------------- BOOL TCIRowsetIdentity::GetBookmark ( DBCOUNTITEM ulRow, DBBKMARK *pcbBookmark, BYTE **ppBookmark ) { BOOL fPass = FALSE; HROW hRow[1]; HROW *pHRow = hRow; DBCOUNTITEM cCount = 0; DBREFCOUNT cRefCount = 0; //the rowset has to expose IRowset in order to have bookmark if(!m_pIRowset) return FALSE; //ulRow has to start with 1 if(!pcbBookmark || !ppBookmark || !ulRow) return FALSE; //restart the cursor position if(!CHECK(m_pIRowset->RestartPosition(NULL),S_OK)) return FALSE; //fetch the row if(!CHECK(m_pIRowset->GetNextRows(NULL,(ulRow-(ULONG)1),1,&cCount,&pHRow),S_OK)) return FALSE; //only one row handle is retrieved COMPARE(cCount, 1); //get the bookmark by the row handle fPass=GetBookmarkByRow(*pHRow, pcbBookmark, ppBookmark); //release the row handle CHECK(m_pIRowset->ReleaseRows(1,pHRow,NULL,NULL,&cRefCount),S_OK); COMPARE(cRefCount, 0); return fPass; } //-------------------------------------------------------------------- //@mfun: Get the bookmark for the row. The function has to be called // after the GetRowsetAndAccessor that creates an accessor on the // rowset. The accessor as to binds the 0th column on the rowset. // //-------------------------------------------------------------------- BOOL TCIRowsetIdentity::GetBookmarkByRow ( HROW hRow, DBBKMARK *pcbBookmark, BYTE **ppBookmark ) { BOOL fPass = FALSE; void *pData = NULL; HACCESSOR hAccessor = NULL; DBCOUNTITEM cBinding = 0; DBLENGTH cbRowSize = 0; DBBINDING *pBinding = NULL; LONG_PTR lColToBind = 0; //the rowset has to expose IRowset in order to have bookmark if(!m_pIRowset) return FALSE; //check the input if(!pcbBookmark || !ppBookmark) return FALSE; //create an accessor to binding the bookmark if(!CHECK(GetAccessorAndBindings(m_pIAccessor, DBACCESSOR_ROWDATA, &hAccessor, &pBinding, &cBinding,&cbRowSize,DBPART_VALUE|DBPART_STATUS|DBPART_LENGTH, USE_COLS_TO_BIND_ARRAY, FORWARD, NO_COLS_BY_REF, NULL, NULL, NULL, DBTYPE_EMPTY, 1, (LONG_PTR *)&lColToBind),S_OK)) goto END; //allocate memory if(!(pData=PROVIDER_ALLOC(cbRowSize))) goto END; //get the data if(!CHECK(m_pIRowset->GetData(hRow, hAccessor, pData),S_OK)) goto END; //get the length of the bookmark // *pcbBookmark= *((ULONG *)(dwAddr+pBinding[0].obLength)); *pcbBookmark=LENGTH_BINDING(pBinding[0], pData); //allocate memory for bookmark *ppBookmark=(BYTE *)PROVIDER_ALLOC(*pcbBookmark); if(!(*ppBookmark)) goto END; //copy the value of the bookmark into the consumer's buffer // memcpy(*ppBookmark, (void *)(dwAddr+pBinding[0].obValue), *pcbBookmark); memcpy(*ppBookmark, &VALUE_BINDING(pBinding[0], pData), (size_t)*pcbBookmark); fPass=TRUE; END: //release the memory if(pData) PROVIDER_FREE(pData); if(pBinding) PROVIDER_FREE(pBinding); //free the accessor CHECK(m_pIAccessor->ReleaseAccessor(hAccessor,NULL),S_OK); return fPass; } //-------------------------------------------------------------------- // //@mfunc: Get cursor type of the rowset. Has to be called after a rowset // generated. // // //-------------------------------------------------------------------- ECURSOR TCIRowsetIdentity::GetCursorType() { IRowsetInfo *pIRowsetInfo = NULL; ULONG cProperty = 0; DBPROPID rgGuid[4]; DBPROPIDSET DBPropIDSet; DBPROPSET *pDBPropSet = NULL; ECURSOR eCursor = FORWARD_ONLY_CURSOR; //initialization rgGuid[0]=DBPROP_OTHERINSERT; rgGuid[1]=DBPROP_OTHERUPDATEDELETE; rgGuid[2]=DBPROP_CANSCROLLBACKWARDS; rgGuid[3]=DBPROP_CANFETCHBACKWARDS; DBPropIDSet.guidPropertySet=DBPROPSET_ROWSET; DBPropIDSet.cPropertyIDs=4; DBPropIDSet.rgPropertyIDs=rgGuid; //QI for IRowsetInfo interface if(!VerifyInterface(m_pIRowset, IID_IRowsetInfo, ROWSET_INTERFACE, (IUnknown**)&pIRowsetInfo)) { goto END; } //ask for the 3 properties pIRowsetInfo->GetProperties(1,&DBPropIDSet,&cProperty,&pDBPropSet); //only one property set should be returned if(!COMPARE(cProperty, 1)) goto END; if(V_BOOL(&pDBPropSet[0].rgProperties[0].vValue)==VARIANT_TRUE) eCursor=DYNAMIC_CURSOR; else { if(V_BOOL(&pDBPropSet[0].rgProperties[1].vValue)==VARIANT_TRUE) eCursor=KEYSET_DRIVEN_CURSOR; else { if( (V_BOOL(&pDBPropSet[0].rgProperties[2].vValue)==VARIANT_TRUE) || (V_BOOL(&pDBPropSet[0].rgProperties[3].vValue)==VARIANT_TRUE) ) { eCursor=STATIC_CURSOR; } } } END: FreeProperties(&cProperty,&pDBPropSet); SAFE_RELEASE(pIRowsetInfo); return eCursor; } //-------------------------------------------------------------------- // //@mfunc: Return TRUE is we are on QueryBased Update mode. Has to // to called after a rowset is created. // ////-------------------------------------------------------------------- BOOL TCIRowsetIdentity::QueryBasedUpdate() { IRowsetInfo *pIRowsetInfo = NULL; ULONG cProperty = 0; DBPROPID DBPropID = KAGPROP_QUERYBASEDUPDATES; DBPROPIDSET DBPropIDSet; DBPROPSET *pDBPropSet = NULL; BOOL fSupported = FALSE; HRESULT hr; //initialize DBPropIDSet.guidPropertySet=DBPROPSET_PROVIDERROWSET; DBPropIDSet.cPropertyIDs=1; DBPropIDSet.rgPropertyIDs=&DBPropID; //QI for IRowsetInfo interface if(!VerifyInterface(m_pIRowset, IID_IRowsetInfo, ROWSET_INTERFACE, (IUnknown**)&pIRowsetInfo)) { } //ask for KAGPROP_QUERYBASEDUPDATES hr = pIRowsetInfo->GetProperties(1,&DBPropIDSet,&cProperty,&pDBPropSet); if(V_BOOL(&pDBPropSet->rgProperties->vValue)==VARIANT_TRUE&&hr==S_OK) fSupported=TRUE; else fSupported=FALSE; FreeProperties(&cProperty,&pDBPropSet); SAFE_RELEASE(pIRowsetInfo); return fSupported; } //-------------------------------------------------------------------- // //@mfunc: Get BOOL value for Property // ////-------------------------------------------------------------------- BOOL TCIRowsetIdentity::GetBoolPropValForRowset(DBPROPID eProp) { IRowsetInfo *pIRowsetInfo = NULL; ULONG cProperty = 0; DBPROPID DBPropID = eProp; DBPROPIDSET DBPropIDSet; DBPROPSET *pDBPropSet = NULL; BOOL fSupported = FALSE; HRESULT hr = S_OK; //initialize DBPropIDSet.guidPropertySet=DBPROPSET_ROWSET; DBPropIDSet.cPropertyIDs=1; DBPropIDSet.rgPropertyIDs=&DBPropID; //QI for IRowsetInfo interface if(!VerifyInterface(m_pIRowset, IID_IRowsetInfo, ROWSET_INTERFACE, (IUnknown**)&pIRowsetInfo)) { } //ask for in Prop hr = pIRowsetInfo->GetProperties(1,&DBPropIDSet,&cProperty,&pDBPropSet); if(V_BOOL(&pDBPropSet->rgProperties->vValue)==VARIANT_TRUE&&hr==S_OK) fSupported=TRUE; else fSupported=FALSE; FreeProperties(&cProperty,&pDBPropSet); SAFE_RELEASE(pIRowsetInfo); return fSupported; } //-------------------------------------------------------------------- // //@mfunc: Get non-key and updatable column ordinals arrays. // // The function allocation memory for the ordinals array. Return // TRUE is one or more non-key and updatable column exists; // FALSE otherwise. // // //-------------------------------------------------------------------- BOOL TCIRowsetIdentity::GetNonKeyAndUpdatable( DBORDINAL *pcbCol, //[out] the count of the rgColNum DBORDINAL **prgColNum, //[out] the col ordinals array IMalloc *pIMalloc ) { DBORDINAL cColsCount; //make sure the columns infomation has been retrieved and //there is at least one column in the rowset if(!m_rgInfo || !m_cRowsetCols) return FALSE; //initialization *pcbCol=0; *prgColNum=(DBORDINAL *)pIMalloc->Alloc(sizeof(DBORDINAL) * m_cRowsetCols); for(cColsCount=0;cColsCountReleaseAccessor(m_hAccessor,NULL), S_OK); else { //QI for the accessor handle on the command object if(!VerifyInterface(m_pIRowset, IID_IAccessor, ROWSET_INTERFACE, (IUnknown**)&pIAccessor)) { CHECK(pIAccessor->ReleaseAccessor(m_hAccessor,NULL), S_OK); SAFE_RELEASE(pIAccessor); } } m_hAccessor=NULL; } //free binding structure if(m_rgBinding) { PROVIDER_FREE(m_rgBinding); m_rgBinding=NULL; } } //-------------------------------------------------------------------- //@mfunc: release a rowset object and accessor created on it // //-------------------------------------------------------------------- void TCIRowsetIdentity::ReleaseRowsetAndAccessor() { IAccessor *pIAccessor; //reset m_cRowset to 0 so that provider will allocate memory for next time m_cRowSize=0; m_cBinding=0; //free the consumer buffer if(m_pData) { PROVIDER_FREE(m_pData); m_pData=NULL; } //free accessor handle if(m_hAccessor) { //if the accessor is created on the rowset object, use the IAccssor //pointer directly to release the accessor handle if(m_eAccessorLocation!=ON_COMMAND_ACCESSOR) CHECK(m_pIAccessor->ReleaseAccessor(m_hAccessor,NULL), S_OK); else { //QI for the accessor handle on the command object if(!VerifyInterface(m_pIRowset, IID_IAccessor, ROWSET_INTERFACE, (IUnknown**)&pIAccessor)) { CHECK(pIAccessor->ReleaseAccessor(m_hAccessor,NULL), S_OK); SAFE_RELEASE(pIAccessor); } } m_hAccessor=NULL; } //release Rowset pointers SAFE_RELEASE(m_pIRowset); SAFE_RELEASE(m_pIRowsetIdentity); SAFE_RELEASE(m_pIRowsetChange); SAFE_RELEASE(m_pIRowsetUpdate); SAFE_RELEASE(m_pIRowsetLocate); //free binding structure PROVIDER_FREE(m_rgBinding); PROVIDER_FREE(m_rgInfo); PROVIDER_FREE(m_pStringsBuffer); ReleaseRowsetObject(0); ReleaseCommandObject(0); } //-------------------------------------------------------------------- // @mfunc base class IsPropertySet // BOOL TCIRowsetIdentity::IsPropertySet(GUID propset, DBPROPID propid, IUnknown * pIUnknown, LONG lValue) { HRESULT hr = E_FAIL; BOOL fSucceed = FALSE; ICommandProperties *pICmdProperties = NULL; IDBProperties * pIDBProperties = NULL; IRowsetInfo * pIRowsetInfo = NULL; DBPROPIDSET rgPropertyIDSet[1]; DBPROPID * rgPropertyIDs; ULONG cPropertySets = 0; DBPROPSET * rgPropertySets = NULL; // Init for Properties rgPropertyIDs = &propid; rgPropertyIDSet->guidPropertySet = propset; rgPropertyIDSet->cPropertyIDs = 1; rgPropertyIDSet->rgPropertyIDs = rgPropertyIDs; // Check to set what DBPROPSET is passed in if( !(memcmp(&propset, &(DBPROPSET_DATASOURCEINFO), sizeof(GUID))) ) { // Make sure the DSO object is valid if( !g_pIDBCreateSession ) goto CLEANUP; // Get a IDBProperties pointer if(!VerifyInterface(g_pIDBCreateSession, IID_IDBProperties, DATASOURCE_INTERFACE, (IUnknown**)&pIDBProperties)) { } // GetProperties hr=pIDBProperties->GetProperties(1, rgPropertyIDSet, &cPropertySets, &rgPropertySets); } else if( (!(memcmp(&propset, &(DBPROPSET_ROWSET), sizeof(GUID)))) && (!pIUnknown) ) { // Make sure the Command object is valid if( !g_pCTable->m_pICommand ) goto CLEANUP; // Get a ICommandProperties pointer if(!VerifyInterface(g_pCTable->m_pICommand, IID_ICommandProperties, COMMAND_INTERFACE, (IUnknown**)&pICmdProperties)) { goto CLEANUP; } // GetProperties hr=pICmdProperties->GetProperties(1, rgPropertyIDSet, &cPropertySets, &rgPropertySets); } else if( (!(memcmp(&propset, &(DBPROPSET_ROWSET), sizeof(GUID)))) && (pIUnknown) ) { // Get a IRosetInfo pointer if(!VerifyInterface(pIUnknown, IID_IRowsetInfo, ROWSET_INTERFACE, (IUnknown**)&pIRowsetInfo)) { } // GetProperties hr=pIRowsetInfo->GetProperties(1, rgPropertyIDSet, &cPropertySets, &rgPropertySets); } else ASSERT(!("Please add DBPROPSET to if statement")); // Check to see if the Property is Supported and set to TRUE if( rgPropertySets[0].rgProperties->vValue.vt == VT_BOOL ) { if( (hr == S_OK) && (rgPropertySets[0].rgProperties->dwStatus == DBPROPSTATUS_OK) && ((V_BOOL(&rgPropertySets[0].rgProperties->vValue)) == VARIANT_TRUE) ) fSucceed = TRUE; } else if( (hr == S_OK) && (rgPropertySets[0].rgProperties->dwStatus == DBPROPSTATUS_OK) && ((V_I4(&rgPropertySets[0].rgProperties->vValue)) == lValue) ) fSucceed = TRUE; PRVTRACE(L"[Propid=%d],[dwOptions=%d],[dwStatus=%d]\n", rgPropertySets[0].rgProperties->dwPropertyID, rgPropertySets[0].rgProperties->dwOptions, rgPropertySets[0].rgProperties->dwStatus); CLEANUP: // Release the Properties pointer SAFE_RELEASE(pIRowsetInfo); SAFE_RELEASE(pICmdProperties); SAFE_RELEASE(pIDBProperties); // Clear the Property memory FreeProperties(&cPropertySets, &rgPropertySets); return fSucceed; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Test Case Section // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // {{ TCW_TEST_CASE_MAP(Boundary) //-------------------------------------------------------------------- // @class Test boundary conditons // class Boundary : public TCIRowsetIdentity { private: // @cmember Static array of variations DECLARE_TEST_CASE_DATA(); public: // {{ TCW_DECLARE_FUNCS // @cmember Execution Routine DECLARE_TEST_CASE_FUNCS(Boundary,TCIRowsetIdentity); // }} // @cmember Initialization Routine virtual BOOL Init(); // @cmember Termination Routine virtual BOOL Terminate(); // {{ TCW_TESTVARS() // @cmember hThisRow is released int Variation_1(); // @cmember hThatRow is released int Variation_2(); // @cmember hThisRow is hard-deleted int Variation_3(); // @cmember hThatRow is hard-deleted int Variation_4(); // @cmember Compare with same row handle. S_OK. int Variation_5(); // @cmember hThisRow is DB_INVALID_HROW int Variation_6(); // @cmember hThatRow is DB_INVALID_HROW int Variation_7(); // @cmember hRow is NULL int Variation_8(); // }} }; // {{ TCW_TESTCASE(Boundary) #define THE_CLASS Boundary BEG_TEST_CASE(Boundary, TCIRowsetIdentity, L"Test boundary conditons") TEST_VARIATION(1, L"hThisRow is released") TEST_VARIATION(2, L"hThatRow is released") TEST_VARIATION(3, L"hThisRow is hard-deleted") TEST_VARIATION(4, L"hThatRow is hard-deleted") TEST_VARIATION(5, L"Compare with same row handle. S_OK.") TEST_VARIATION(6, L"hThisRow is DB_INVALID_HROW") TEST_VARIATION(7, L"hThatRow is DB_INVALID_HROW") TEST_VARIATION(8, L"hRow is NULL") END_TEST_CASE() #undef THE_CLASS // }} // }} // {{ TCW_TEST_CASE_MAP(Transaction) //-------------------------------------------------------------------- // @class test zomibe and fully functional state after a trasaction // class Transaction : public CTransaction { private: // @cmember Static array of variations DECLARE_TEST_CASE_DATA(); DBPROPSET m_DBPropSet; BOOL m_fTrans; public: // {{ TCW_DECLARE_FUNCS // @cmember Execution Routine DECLARE_TEST_CASE_FUNCS(Transaction,CTransaction); // }} // @cmember Initialization Routine virtual BOOL Init(); // @cmember Termination Routine virtual BOOL Terminate(); // {{ TCW_TESTVARS() // @cmember Commit with Retaining. Test on two identical hrows. S_OK or E_UNEXPECTED int Variation_1(); // @cmember Commit without Retaining. Test on two different hrows. S_FALSE or E_UNEXPECTED. int Variation_2(); // @cmember Abort with Retaining. Test on one hard deleted row handle and one row handle. DB_E_DELETEDROW or E_UNEXPECTED. int Variation_3(); // @cmember Abort without Retaining. Test on one changed row handle and one row handle that refers to the same row. S_OK or E_UNEXPECTE int Variation_4(); // }} }; // {{ TCW_TESTCASE(Transaction) #define THE_CLASS Transaction BEG_TEST_CASE(Transaction, CTransaction, L"test zomibe and fully functional state after a trasaction") TEST_VARIATION(1, L"Commit with Retaining. Test on two identical hrows. S_OK or E_UNEXPECTED") TEST_VARIATION(2, L"Commit without Retaining. Test on two different hrows. S_FALSE or E_UNEXPECTED.") TEST_VARIATION(3, L"Abort with Retaining. Test on one hard deleted row handle and one row handle. DB_E_DELETEDROW or E_UNEXPECTED.") TEST_VARIATION(4, L"Abort without Retaining. Test on one changed row handle and one row handle that refers to the same row. S_OK or E_UNEXPECTE") END_TEST_CASE() #undef THE_CLASS // }} // }} // {{ TCW_TEST_CASE_MAP(SchemaRowset) //-------------------------------------------------------------------- // @class SchemaRowset // class SchemaRowset : public TCIRowsetIdentity { private: // @cmember Static array of variations DECLARE_TEST_CASE_DATA(); public: // {{ TCW_DECLARE_FUNCS // @cmember Execution Routine DECLARE_TEST_CASE_FUNCS(SchemaRowset,TCIRowsetIdentity); // }} // @cmember Initialization Routine virtual BOOL Init(); // @cmember Termination Routine virtual BOOL Terminate(); // {{ TCW_TESTVARS() // @cmember SchemaRowset int Variation_1(); // }} }; // {{ TCW_TESTCASE(SchemaRowset) #define THE_CLASS SchemaRowset BEG_TEST_CASE(SchemaRowset, TCIRowsetIdentity, L"SchemaRowset") TEST_VARIATION(1, L"SchemaRowset") END_TEST_CASE() #undef THE_CLASS // }} // }} // {{ TCW_TEST_CASE_MAP(Forward_Only_Cursor) //-------------------------------------------------------------------- // @class Forward_Only_Cursor // class Forward_Only_Cursor : public TCIRowsetIdentity { private: // @cmember Static array of variations DECLARE_TEST_CASE_DATA(); public: // {{ TCW_DECLARE_FUNCS // @cmember Execution Routine DECLARE_TEST_CASE_FUNCS(Forward_Only_Cursor,TCIRowsetIdentity); // }} // @cmember Initialization Routine virtual BOOL Init(); // @cmember Termination Routine virtual BOOL Terminate(); // {{ TCW_TESTVARS() // @cmember Fetch two different rows. S_FALSE. int Variation_1(); // @cmember Multiple rows fetched 2 different times. int Variation_2(); // @cmember REMOVEDELETED FALSE int Variation_3(); // @cmember REMOVEDELETED TRUE int Variation_4(); // @cmember QI without DBPROP_IRowsetIdentity requested int Variation_5(); // }} }; // {{ TCW_TESTCASE(Forward_Only_Cursor) #define THE_CLASS Forward_Only_Cursor BEG_TEST_CASE(Forward_Only_Cursor, TCIRowsetIdentity, L"Forward_Only_Cursor") TEST_VARIATION(1, L"Fetch two different rows. S_FALSE.") TEST_VARIATION(2, L"Multiple rows fetched 2 different times.") TEST_VARIATION(3, L"REMOVEDELETED FALSE.") TEST_VARIATION(4, L"REMOVEDELETED TRUE.") TEST_VARIATION(5, L"QI without DBPROP_IRowsetIdentity requested.") END_TEST_CASE() #undef THE_CLASS // }} // }} // {{ TCW_TEST_CASE_MAP(Static_Query_Immediate) //-------------------------------------------------------------------- // @class Static_Query_Immediate // class Static_Query_Immediate : public TCIRowsetIdentity { private: // @cmember Static array of variations DECLARE_TEST_CASE_DATA(); public: // {{ TCW_DECLARE_FUNCS // @cmember Execution Routine DECLARE_TEST_CASE_FUNCS(Static_Query_Immediate,TCIRowsetIdentity); // }} // @cmember Initialization Routine virtual BOOL Init(); // @cmember Termination Routine virtual BOOL Terminate(); // {{ TCW_TESTVARS() // @cmember Fetch one row. Move the cursor and fetch backwards to retrieve the same row handle. S_OK. int Variation_1(); // @cmember Hard deleted the 1st row handle. Fetch the same row again.. int Variation_2(); // }} }; // {{ TCW_TESTCASE(Static_Query_Immediate) #define THE_CLASS Static_Query_Immediate BEG_TEST_CASE(Static_Query_Immediate, TCIRowsetIdentity, L"Static_Query_Immediate") TEST_VARIATION(1, L"Fetch one row. Move the cursor and fetch backwards to retrieve the same row handle. S_OK. ") TEST_VARIATION(2, L"Hard deleted the 1st row handle. Fetch the same row again.") END_TEST_CASE() #undef THE_CLASS // }} // }} // {{ TCW_TEST_CASE_MAP(Static_Cursor_Buffered) //-------------------------------------------------------------------- // @class Static_Cursor_Buffered // class Static_Cursor_Buffered : public TCIRowsetIdentity { private: // @cmember Static array of variations DECLARE_TEST_CASE_DATA(); public: // {{ TCW_DECLARE_FUNCS // @cmember Execution Routine DECLARE_TEST_CASE_FUNCS(Static_Cursor_Buffered,TCIRowsetIdentity); // }} // @cmember Initialization Routine virtual BOOL Init(); // @cmember Termination Routine virtual BOOL Terminate(); // {{ TCW_TESTVARS() // @cmember Soft deleted the 1st row handle. Fetch the same row again by IRowsetLocate::GetRowsAt. S_OK. int Variation_1(); // @cmember Fetch hRowThis and soft change the row. The row should stay in place in the rowset. Fetch the row handle again in hRowThat int Variation_2(); // @cmember Insert a new row. Compare it with a new row handle. int Variation_3(); // }} }; // {{ TCW_TESTCASE(Static_Cursor_Buffered) #define THE_CLASS Static_Cursor_Buffered BEG_TEST_CASE(Static_Cursor_Buffered, TCIRowsetIdentity, L"Static_Cursor_Buffered") TEST_VARIATION(1, L"Soft deleted the 1st row handle. Fetch the same row again") TEST_VARIATION(2, L"Fetch hRowThis and soft change the row. The row should stay in place in the rowset. Fetch the row handle again in hRowThat") TEST_VARIATION(3, L"Insert a new row. Compare it with a new row handle.") END_TEST_CASE() #undef THE_CLASS // }} // }} // {{ TCW_TEST_CASE_MAP(Keyset_Query_Immediate) //-------------------------------------------------------------------- // @class Keyset_Query_Immediate // class Keyset_Query_Immediate : public TCIRowsetIdentity { private: // @cmember Static array of variations DECLARE_TEST_CASE_DATA(); public: // {{ TCW_DECLARE_FUNCS // @cmember Execution Routine DECLARE_TEST_CASE_FUNCS(Keyset_Query_Immediate,TCIRowsetIdentity); // }} // @cmember Initialization Routine virtual BOOL Init(); // @cmember Termination Routine virtual BOOL Terminate(); // {{ TCW_TESTVARS() // @cmember Fetch one row. Move the cursor and fetch backwards to retrieve the same row handle. S_OK. int Variation_1(); // @cmember Fetch hRowThis and change a non-key value. Fetch the same row in hRowThat by IRowsetLocate::GetRowsByBookmark. S_OK. int Variation_2(); // @cmember Hard deleted the 1st row handle. Fetch the same row again forwards. int Variation_3(); // @cmember Hard deleted the 1st row handle. Fetch the same row again backwards. int Variation_4(); // @cmember Hard deleted the last row handle. Fetch the same row again backwards. int Variation_5(); // @cmember Hard deleted the last row handle. Fetch the same row again forwards. int Variation_6(); // }} }; // {{ TCW_TESTCASE(Keyset_Query_Immediate) #define THE_CLASS Keyset_Query_Immediate BEG_TEST_CASE(Keyset_Query_Immediate, TCIRowsetIdentity, L"Keyset_Query_Immediate") TEST_VARIATION(1, L"Fetch one row. Move the cursor and fetch backwards to retrieve the same row handle. S_OK. ") TEST_VARIATION(2, L"Fetch hRowThis and change a non-key value. Fetch the same row in hRowThat by IRowsetLocate::GetRowsByBookmark. S_OK.") TEST_VARIATION(3, L"Hard deleted the 1st row handle. Fetch the same row again forwards.") TEST_VARIATION(4, L"Hard deleted the 1st row handle. Fetch the same row again backwards.") TEST_VARIATION(5, L"Hard deleted the last row handle. Fetch the same row again backwards.") TEST_VARIATION(6, L"Hard deleted the last row handle. Fetch the same row again forwards.") END_TEST_CASE() #undef THE_CLASS // }} // }} // {{ TCW_TEST_CASE_MAP(Keyset_Cursor_Buffered) //-------------------------------------------------------------------- // @class Keyset_Cursor_Buffered // class Keyset_Cursor_Buffered : public TCIRowsetIdentity { private: // @cmember Static array of variations DECLARE_TEST_CASE_DATA(); public: // {{ TCW_DECLARE_FUNCS // @cmember Execution Routine DECLARE_TEST_CASE_FUNCS(Keyset_Cursor_Buffered,TCIRowsetIdentity); // }} // @cmember Initialization Routine virtual BOOL Init(); // @cmember Termination Routine virtual BOOL Terminate(); // {{ TCW_TESTVARS() // @cmember Fetch one row. Move the cursor and fetch backwards to retrieve the same row handle by IRowsetLocate::GetRowsByBookmark. S_OK. int Variation_1(); // @cmember Soft deleted the 1st row handle. Use Bookmarks. int Variation_2(); // @cmember Fetch hRowThis and change a non-key value. Fetch the same row in hRowThat. IsSameRow should return S_OK. int Variation_3(); // @cmember Insert a new row into the rowset - Undo. int Variation_4(); // @cmember Fetch hRowThis and soft change the key of the row. The row should be deleted and a new row is appended at the end of rowset. int Variation_5(); // @cmember Insert a new row into the rowset - Update. int Variation_6(); // @cmember Soft deleted the 1st row handle. int Variation_7(); // }} }; // {{ TCW_TESTCASE(Keyset_Cursor_Buffered) #define THE_CLASS Keyset_Cursor_Buffered BEG_TEST_CASE(Keyset_Cursor_Buffered, TCIRowsetIdentity, L"Keyset_Cursor_Buffered") TEST_VARIATION(1, L"Fetch one row. Move the cursor and fetch backwards to retrieve the same row handle by IRowsetLocate::GetRowsByBookmark. S_OK.") TEST_VARIATION(2, L"Soft deleted the 1st row handle. Use Bookmarks.") TEST_VARIATION(3, L"Fetch hRowThis and change a non-key value. Fetch the same row in hRowThat. IsSameRow should return S_OK. ") TEST_VARIATION(4, L"Insert a new row into the rowset - Undo.") TEST_VARIATION(5, L"Fetch hRowThis and soft change the key of the row. The row should be deleted and a new row is appended at the end of rowset.") TEST_VARIATION(6, L"Insert a new row into the rowset - Update.") TEST_VARIATION(7, L"Soft deleted the 1st row handle") END_TEST_CASE() #undef THE_CLASS // }} // }} // {{ TCW_TEST_CASE_MAP(Dynamic_Query_Buffered) //-------------------------------------------------------------------- // @class Dynamic_Query_Buffered // class Dynamic_Query_Buffered : public TCIRowsetIdentity { private: // @cmember Static array of variations DECLARE_TEST_CASE_DATA(); public: // {{ TCW_DECLARE_FUNCS // @cmember Execution Routine DECLARE_TEST_CASE_FUNCS(Dynamic_Query_Buffered,TCIRowsetIdentity); // }} // @cmember Initialization Routine virtual BOOL Init(); // @cmember Termination Routine virtual BOOL Terminate(); // {{ TCW_TESTVARS() // @cmember Soft-delete one row. S_FALSE. Call IRowsetUpdate::Update. DB_E_DELETEDROW. int Variation_1(); // }} }; // {{ TCW_TESTCASE(Dynamic_Query_Buffered) #define THE_CLASS Dynamic_Query_Buffered BEG_TEST_CASE(Dynamic_Query_Buffered, TCIRowsetIdentity, L"Dynamic_Query_Buffered") TEST_VARIATION(1, L"Soft-delete one row. S_FALSE. Call IRowsetUpdate::Update. DB_E_DELETEDROW.") END_TEST_CASE() #undef THE_CLASS // }} // }} // {{ TCW_TEST_CASE_MAP(Dynamic_Cursor_Immediate) //-------------------------------------------------------------------- // @class Dynamic_Cursor_Immediate // class Dynamic_Cursor_Immediate : public TCIRowsetIdentity { private: // @cmember Static array of variations DECLARE_TEST_CASE_DATA(); public: // {{ TCW_DECLARE_FUNCS // @cmember Execution Routine DECLARE_TEST_CASE_FUNCS(Dynamic_Cursor_Immediate,TCIRowsetIdentity); // }} // @cmember Initialization Routine virtual BOOL Init(); // @cmember Termination Routine virtual BOOL Terminate(); // {{ TCW_TESTVARS() // @cmember Hard-delete one row. S_FALSE. int Variation_1(); // }} }; // {{ TCW_TESTCASE(Dynamic_Cursor_Immediate) #define THE_CLASS Dynamic_Cursor_Immediate BEG_TEST_CASE(Dynamic_Cursor_Immediate, TCIRowsetIdentity, L"Dynamic_Cursor_Immediate") TEST_VARIATION(1, L"Hard-delete one row. S_FALSE..") END_TEST_CASE() #undef THE_CLASS // }} // }} // {{ TCW_TEST_CASE_MAP(ExtendedErrors) //-------------------------------------------------------------------- // @class Extended Errors // class ExtendedErrors : public TCIRowsetIdentity { private: // @cmember Static array of variations DECLARE_TEST_CASE_DATA(); public: // {{ TCW_DECLARE_FUNCS // @cmember Execution Routine DECLARE_TEST_CASE_FUNCS(ExtendedErrors,TCIRowsetIdentity); // }} // @cmember Initialization Routine virtual BOOL Init(); // @cmember Termination Routine virtual BOOL Terminate(); // {{ TCW_TESTVARS() // @cmember Valid IRowsetIdentity calls with previous error object existing. int Variation_1(); // @cmember Invalid IRowsetIdentity calls with previous error object existing int Variation_2(); // @cmember Invalid IRowsetIdentity calls with no previous error object existing int Variation_3(); // }} }; // {{ TCW_TESTCASE(ExtendedErrors) #define THE_CLASS ExtendedErrors BEG_TEST_CASE(ExtendedErrors, TCIRowsetIdentity, L"Extended Errors") TEST_VARIATION(1, L"Valid IRowsetIdentity calls with previous error object existing.") TEST_VARIATION(2, L"Invalid IRowsetIdentity calls with previous error object existing") TEST_VARIATION(3, L"Invalid IRowsetIdentity calls with no previous error object existing") END_TEST_CASE() #undef THE_CLASS // }} // }} // }} END_DECLARE_TEST_CASES() // {{ TCW_TESTMODULE(ThisModule) TEST_MODULE(11, ThisModule, gwszModuleDescrip) TEST_CASE(1, Boundary) TEST_CASE(2, Transaction) TEST_CASE(3, SchemaRowset) TEST_CASE(4, Forward_Only_Cursor) TEST_CASE(5, Static_Query_Immediate) TEST_CASE(6, Static_Cursor_Buffered) TEST_CASE(7, Keyset_Query_Immediate) TEST_CASE(8, Keyset_Cursor_Buffered) TEST_CASE(9, Dynamic_Query_Buffered) TEST_CASE(10, Dynamic_Cursor_Immediate) TEST_CASE(11, ExtendedErrors) END_TEST_MODULE() // }} // {{ TCW_TC_PROTOTYPE(Boundary) //*----------------------------------------------------------------------- //| Test Case: Boundary - Test boundary conditons //| Created: 05/28/96 //*----------------------------------------------------------------------- //-------------------------------------------------------------------- // @mfunc TestCase Initialization Routine // // @rdesc TRUE or FALSE // BOOL Boundary::Init() { DBPROPID rgGuid[2]; ULONG cProp=1; rgGuid[0]=DBPROP_IRowsetIdentity; if(!TCIRowsetIdentity::Init()) return FALSE; //For read only provider or IRowsetChange not available, skip this variation //this is now a little redundant because a simialr check was just added to //function GetRowsetAndAccessor if(!(g_fReadOnlyProvider) && g_fROWSETUPDATABLE) { rgGuid[1]=DBPROP_IRowsetChange; cProp++; } //get a rowset with IID_IRowsetIdentity if(!GetRowsetAndAccessor(USE_OPENROWSET, cProp,rgGuid,0,NULL,NO_ACCESSOR)) { return FALSE; } else { return TRUE; } } // {{ TCW_VAR_PROTOTYPE(1) //*----------------------------------------------------------------------- // @mfunc hThisRow is released // // @rdesc TEST_PASS or TEST_FAIL // int Boundary::Variation_1() { HROW *pHRow =NULL; DBCOUNTITEM cRows =0; BOOL fTestPass =FALSE; HRESULT hr; //if this test variation is not valid if (!g_fTestValid) { odtLog << L"The Provider does not support the properties that are necessary for this variation to execute.\n"; return TEST_PASS; } //Restart the position to the begining of the rowset hr = m_pIRowset->RestartPosition(NULL); if (S_OK!=hr && DB_S_COMMANDREEXECUTED!=hr) { goto END; } //get two row handles if(!CHECK(m_pIRowset->GetNextRows(NULL,0,2,&cRows,&pHRow),S_OK)) { goto END; } //release the 2nd row handle if(!CHECK(m_pIRowset->ReleaseRows(1,&(pHRow[1]),NULL,NULL,NULL),S_OK)) { goto END; } pHRow[1]=NULL; //mark the active row handles cRows--; //IsSameRow should return DB_E_BADROWHANDLE if(!CHECK(m_pIRowsetIdentity->IsSameRow(pHRow[1], *pHRow),DB_E_BADROWHANDLE)) { goto END; } //binary comparision if(CompareHandlesByLiteral(pHRow[1], *pHRow,FALSE,FALSE)) { fTestPass=TRUE; } END: if(pHRow) { CHECK(m_pIRowset->ReleaseRows(cRows, pHRow, NULL,NULL,NULL),S_OK); PROVIDER_FREE(pHRow); } if(fTestPass) { return TEST_PASS; } else { return TEST_FAIL; } } // }} // {{ TCW_VAR_PROTOTYPE(2) //*----------------------------------------------------------------------- // @mfunc hThatRow is released // // @rdesc TEST_PASS or TEST_FAIL // int Boundary::Variation_2() { HROW *pHRow = NULL; DBCOUNTITEM cRows = 0; BOOL fTestPass = FALSE; //if this test variation is not valid if (!g_fTestValid) { odtLog << L"The Provider does not support the properties that are necessary for this variation to execute.\n"; return TEST_PASS; } //get two row handles if(!CHECK(m_pIRowset->GetNextRows(NULL,0,2,&cRows,&pHRow),S_OK)) goto END; //release the 2nd row handle if(!CHECK(m_pIRowset->ReleaseRows(1,&(pHRow[1]),NULL,NULL,NULL),S_OK)) goto END; pHRow[1]=NULL; //mark the active row handles cRows--; //IsSameRow should return DB_E_BADROWHANDLE if(!CHECK(m_pIRowsetIdentity->IsSameRow(*pHRow, pHRow[1]),DB_E_BADROWHANDLE)) { goto END; } //binary comparision if(CompareHandlesByLiteral(*pHRow, pHRow[1],FALSE,FALSE)) { fTestPass=TRUE; } END: if(pHRow) { CHECK(m_pIRowset->ReleaseRows(cRows, pHRow, NULL,NULL,NULL),S_OK); PROVIDER_FREE(pHRow); } if(fTestPass) return TEST_PASS; else return TEST_FAIL; } // }} // {{ TCW_VAR_PROTOTYPE(3) //*----------------------------------------------------------------------- // @mfunc hThisRow is hard-deleted // // @rdesc TEST_PASS or TEST_FAIL // int Boundary::Variation_3() { HROW *pHRow = NULL; DBCOUNTITEM cRows = 0; BOOL fTestPass = FALSE; DBROWSTATUS rgRowStatus[1]; //if this test variation is not valid if (!g_fTestValid) { odtLog << L"The Provider does not support the properties that are necessary for this variation to execute.\n"; return TEST_PASS; } //if IRowsetChange not available because conformance won't allow it if (!g_fIRowsetChange) { odtLog << L"Can not get to IRowsetChange, can not insert a row.\n"; return TEST_PASS; } //For read only provider or IRowsetChange not available, skip this variation if(g_fReadOnlyProvider || !(g_fROWSETUPDATABLE)) { odtLog << L"Can not get to IRowsetChange, can not insert a row.\n"; return TEST_PASS; } //get two row handles if(!CHECK(m_pIRowset->GetNextRows(NULL,0,2,&cRows,&pHRow),S_OK)) goto END; //check to see if the DSO is ReadOnly if( IsPropertySet(DBPROPSET_DATASOURCEINFO, DBPROP_DATASOURCEREADONLY, NULL, 0) ) { //try deleting the row handle if(!CHECK(m_pIRowsetChange->DeleteRows(NULL,1,pHRow,rgRowStatus),DB_E_ERRORSOCCURRED) || !COMPARE(rgRowStatus[0], DBROWSTATUS_E_PERMISSIONDENIED)) goto END; //IsSameRow should return S_OK if(!CHECK(m_pIRowsetIdentity->IsSameRow(*pHRow, pHRow[0]), S_OK)) { goto END; } //IsSameRow should return S_FALSE if(!CHECK(m_pIRowsetIdentity->IsSameRow(*pHRow, pHRow[1]), S_FALSE)) { goto END; } //binary comparision if(!CompareHandlesByLiteral(*pHRow, pHRow[0], FALSE, TRUE)) { goto END; } //binary comparision if(!CompareHandlesByLiteral(*pHRow, pHRow[1], FALSE, FALSE)) { goto END; } fTestPass=TRUE; } else { //delete the row handle if(!CHECK(m_pIRowsetChange->DeleteRows(NULL,1,pHRow,rgRowStatus),S_OK) || !COMPARE(rgRowStatus[0], DBROWSTATUS_S_OK)) goto END; //IsSameRow should return DB_E_DELETEDROW if(!CHECK(m_pIRowsetIdentity->IsSameRow(*pHRow, pHRow[0]), DB_E_DELETEDROW)) { goto END; } //IsSameRow should return DB_E_DELETEDROW if(!CHECK(m_pIRowsetIdentity->IsSameRow(*pHRow, pHRow[1]),DB_E_DELETEDROW)) { goto END; } fTestPass=TRUE; } END: CHECK(m_pIRowset->ReleaseRows(cRows, pHRow, NULL,NULL,NULL),S_OK); PROVIDER_FREE(pHRow); if(fTestPass) return TEST_PASS; else return TEST_FAIL; } // }} // {{ TCW_VAR_PROTOTYPE(4) //*----------------------------------------------------------------------- // @mfunc hThatRow is hard-deleted // // @rdesc TEST_PASS or TEST_FAIL // int Boundary::Variation_4() { HROW *pHRow = NULL; DBCOUNTITEM cRows = 0; BOOL fTestPass = FALSE; DBROWSTATUS rgRowStatus[1]; //if this test variation is not valid if (!g_fTestValid) { odtLog << L"The Provider does not support the properties that are necessary for this variation to execute.\n"; return TEST_PASS; } //if IRowsetChange not available because conformance won't allow it if (!g_fIRowsetChange) { odtLog << L"Can not get to IRowsetChange, can not insert a row.\n"; return TEST_PASS; } //if IRowsetChange not available because conformance won't allow it //For read only provider or IRowsetChange not available, skip this variation if(g_fReadOnlyProvider || !(g_fROWSETUPDATABLE)) { odtLog << L"Can not get to IRowsetChange, can not insert a row.\n"; return TEST_PASS; } //get two row handles if(!CHECK(m_pIRowset->GetNextRows(NULL,0,2,&cRows,&pHRow),S_OK)) goto END; //check to see if the DSO is ReadOnly if( IsPropertySet(DBPROPSET_DATASOURCEINFO, DBPROP_DATASOURCEREADONLY, NULL, 0) ) { //try deleting the row handle if(!CHECK(m_pIRowsetChange->DeleteRows(NULL,1,&pHRow[1],rgRowStatus),DB_E_ERRORSOCCURRED) || !COMPARE(rgRowStatus[0], DBROWSTATUS_E_PERMISSIONDENIED)) goto END; //IsSameRow should return S_OK if(!CHECK(m_pIRowsetIdentity->IsSameRow(*pHRow, pHRow[0]), S_OK)) { goto END; } //IsSameRow should return S_FALSE if(!CHECK(m_pIRowsetIdentity->IsSameRow(*pHRow, pHRow[1]), S_FALSE)) { goto END; } //binary comparision if(!CompareHandlesByLiteral(*pHRow, pHRow[0], FALSE, TRUE)) { goto END; } //binary comparision if(!CompareHandlesByLiteral(*pHRow, pHRow[1], FALSE, FALSE)) { goto END; } fTestPass=TRUE; } else { //delete the row handle if(!CHECK(m_pIRowsetChange->DeleteRows(NULL,1,&pHRow[1],rgRowStatus),S_OK) || !COMPARE(rgRowStatus[0], DBROWSTATUS_S_OK)) goto END; //IsSameRow should return DB_E_DELETEDROW if(!CHECK(m_pIRowsetIdentity->IsSameRow(*pHRow, pHRow[0]), S_OK)) { goto END; } //IsSameRow should return DB_E_DELETEDROW if(!CHECK(m_pIRowsetIdentity->IsSameRow(*pHRow, pHRow[1]),DB_E_DELETEDROW)) { goto END; } fTestPass=TRUE; } END: CHECK(m_pIRowset->ReleaseRows(cRows, pHRow, NULL,NULL,NULL),S_OK); PROVIDER_FREE(pHRow); if(fTestPass) return TEST_PASS; else return TEST_FAIL; } // }} // {{ TCW_VAR_PROTOTYPE(5) //*----------------------------------------------------------------------- // @mfunc Compare with same row handle. S_OK. // // @rdesc TEST_PASS or TEST_FAIL // int Boundary::Variation_5() { HROW HRow = NULL; HROW *pHRow = &HRow; DBCOUNTITEM cRows = 0; BOOL fTestPass = FALSE; //if this test variation is not valid if (!g_fTestValid) { odtLog << L"The Provider does not support the properties that are necessary for this variation to execute.\n"; return TEST_PASS; } //get one row handles if(!CHECK(m_pIRowset->GetNextRows(NULL,1,1,&cRows,&pHRow),S_OK)) goto END; //IsSameRow should return S_OK if(!CHECK(m_pIRowsetIdentity->IsSameRow(HRow,HRow),S_OK)) { goto END; } //binary comparision if(CompareHandlesByLiteral(HRow,HRow,FALSE,TRUE)) { fTestPass=TRUE; } END: if(HRow) CHECK(m_pIRowset->ReleaseRows(1, pHRow, NULL,NULL,NULL),S_OK); if(fTestPass) return TEST_PASS; else return TEST_FAIL; } // }} // {{ TCW_VAR_PROTOTYPE(6) //*----------------------------------------------------------------------- // @mfunc hThisRow is DB_INVALID_HROW // // @rdesc TEST_PASS or TEST_FAIL // int Boundary::Variation_6() { HROW HRow = NULL; HROW *pHRow = &HRow; DBCOUNTITEM cRows = 0; BOOL fTestPass = FALSE; //if this test variation is not valid if (!g_fTestValid) { odtLog << L"The Provider does not support the properties that are necessary for this variation to execute.\n"; return TEST_PASS; } //get one row handles if(!CHECK(m_pIRowset->GetNextRows(NULL,1,1,&cRows,&pHRow),S_OK)) { goto END; } //IsSameRow should return DB_E_BADROWHANDLE if(!CHECK(m_pIRowsetIdentity->IsSameRow(DB_NULL_HROW,HRow),DB_E_BADROWHANDLE)) { goto END; } //binary comparision if(CompareHandlesByLiteral(DB_NULL_HROW,HRow,FALSE,FALSE)) { fTestPass=TRUE; } END: if(HRow) { CHECK(m_pIRowset->ReleaseRows(1, pHRow, NULL,NULL,NULL),S_OK); } if(fTestPass) { return TEST_PASS; } else { return TEST_FAIL; } } // }} // {{ TCW_VAR_PROTOTYPE(7) //*----------------------------------------------------------------------- // @mfunc hThatRow is DB_INVALID_HROW // // @rdesc TEST_PASS or TEST_FAIL // int Boundary::Variation_7() { HROW HRow = NULL; HROW *pHRow = &HRow; DBCOUNTITEM cRows = 0; BOOL fTestPass = FALSE; //if this test variation is not valid if (!g_fTestValid) { odtLog << L"The Provider does not support the properties that are necessary for this variation to execute.\n"; return TEST_PASS; } //IsSameRow should return DB_E_BADROWHANDLE if(!CHECK(m_pIRowsetIdentity->IsSameRow(DB_NULL_HROW, DB_NULL_HROW),DB_E_BADROWHANDLE)) { goto END; } //binary comparision if(CompareHandlesByLiteral(DB_NULL_HROW,DB_NULL_HROW,FALSE,FALSE)) { fTestPass=TRUE; } //get one row handles if(!CHECK(m_pIRowset->GetNextRows(NULL,1,1,&cRows,&pHRow),S_OK)) goto END; //IsSameRow should return DB_E_BADROWHANDLE if(!CHECK(m_pIRowsetIdentity->IsSameRow(DB_NULL_HROW, DB_NULL_HROW),DB_E_BADROWHANDLE)) { goto END; } fTestPass=TRUE; END: if(HRow) CHECK(m_pIRowset->ReleaseRows(1, pHRow, NULL,NULL,NULL),S_OK); if(fTestPass) return TEST_PASS; else return TEST_FAIL; } // }} // {{ TCW_VAR_PROTOTYPE(8) //*----------------------------------------------------------------------- // @mfunc hRow is NULL // // @rdesc TEST_PASS or TEST_FAIL // int Boundary::Variation_8() { HRESULT ExpHR = DB_E_BADROWHANDLE; HROW *pHRow = NULL; DBCOUNTITEM cRows = 0; BOOL fTestPass = FALSE; HROW *pHRowTemp; ULONG rgRefCounts = 0; //if this test variation is not valid if( !g_fTestValid ) { odtLog << L"The Provider does not support the properties that are necessary for this variation to execute."<GetNextRows(NULL,1,2,&cRows,&pHRow),S_OK); CHECK(m_pIRowset->ReleaseRows(1, pHRow, NULL, &rgRefCounts, NULL),S_OK); //Check the refcount and change the Expected HRESULT if( !rgRefCounts ) ExpHR = DB_E_BADROWHANDLE; else ExpHR = S_FALSE; //IsSameRow should return DB_E_BADROWHANDLE or S_FALSE TESTC_(m_pIRowsetIdentity->IsSameRow(pHRow[0],pHRow[1]),ExpHR); TESTC(CompareHandlesByLiteral(pHRow[0],pHRow[1],FALSE,FALSE)); //IsSameRow should return DB_E_BADROWHANDLE or S_FALSE TESTC_(m_pIRowsetIdentity->IsSameRow(pHRow[1],pHRow[0]),ExpHR); TESTC(CompareHandlesByLiteral(pHRow[1],pHRow[0],FALSE,FALSE)); //release the sceond row pHRowTemp = &pHRow[1]; CHECK(m_pIRowset->ReleaseRows(1, pHRowTemp, NULL, &rgRefCounts, NULL),S_OK); //Check the refcount and change the Expected HRESULT if( !rgRefCounts ) ExpHR = DB_E_BADROWHANDLE; else ExpHR = S_FALSE; //IsSameRow should return DB_E_BADROWHANDLE or S_FALSE TESTC_(m_pIRowsetIdentity->IsSameRow(pHRow[0],pHRow[1]),ExpHR); TESTC(CompareHandlesByLiteral(pHRow[0],pHRow[1],FALSE,FALSE)); fTestPass=TRUE; CLEANUP: PROVIDER_FREE(pHRow) if(fTestPass) return TEST_PASS; else return TEST_FAIL; } // }} // {{ TCW_TERMINATE_METHOD //-------------------------------------------------------------------- // @mfunc TestCase Termination Routine // // @rdesc TRUE or FALSE // BOOL Boundary::Terminate() { ReleaseRowsetAndAccessor(); return(TCIRowsetIdentity::Terminate()); } // }} // }} // {{ TCW_TC_PROTOTYPE(Transaction) //*----------------------------------------------------------------------- //| Test Case: Transaction - test zomibe and fully functional state after a trasaction //| Created: 05/28/96 //*----------------------------------------------------------------------- //-------------------------------------------------------------------- // @mfunc TestCase Initialization Routine // // @rdesc TRUE or FALSE // BOOL Transaction::Init() { BOOL fPass = FALSE; ULONG j = 0; ULONG i = 0; DBPROPID rgGuid[5]; ULONG cProp = 2; IRowsetIdentity *pIRowsetIdentity = NULL; IRowsetInfo *pIRowsetInfo = NULL; ULONG cProperty = 0; DBPROPID DBPropID; DBPROPIDSET DBPropIDSet; DBPROPSET *pDBPropSet = NULL; BOOL fSupported = FALSE; HRESULT hr = S_OK; // Initialize the array of Properties m_DBPropSet.rgProperties = NULL; m_fTrans = TRUE; if(!CTransaction::Init()) { //it is not an error to not support transactions so return TRUE m_fTrans = FALSE; return TRUE; } m_DBPropSet.guidPropertySet=DBPROPSET_ROWSET; if(!g_fReadOnlyProvider && g_fROWSETUPDATABLE) { cProp++; cProp++; } m_DBPropSet.cProperties=cProp; m_DBPropSet.rgProperties=(DBPROP *)PROVIDER_ALLOC(cProp*sizeof(DBPROP)); //reset cProp and figure is out again so the array index will be correct cProp=2; if(!m_DBPropSet.rgProperties) return FALSE; //set IID_IRowsetIdentity, DBPROP_CANHOLDROWS, //DBPROP_CANFETCHBACKWARDS, IID_IRowsetDelete m_DBPropSet.rgProperties->dwPropertyID=DBPROP_IRowsetIdentity; m_DBPropSet.rgProperties->dwOptions=DBPROPOPTIONS_REQUIRED; m_DBPropSet.rgProperties->vValue.vt=VT_BOOL; m_DBPropSet.rgProperties->colid=DB_NULLID; V_BOOL(&m_DBPropSet.rgProperties->vValue)=VARIANT_TRUE; m_DBPropSet.rgProperties[1].dwPropertyID=DBPROP_CANHOLDROWS; m_DBPropSet.rgProperties[1].dwOptions=DBPROPOPTIONS_REQUIRED; m_DBPropSet.rgProperties[1].vValue.vt=VT_BOOL; m_DBPropSet.rgProperties[1].colid=DB_NULLID; V_BOOL(&m_DBPropSet.rgProperties[1].vValue)=VARIANT_TRUE; if(!g_fReadOnlyProvider && g_fROWSETUPDATABLE) { m_DBPropSet.rgProperties[cProp].dwPropertyID=DBPROP_IRowsetChange; m_DBPropSet.rgProperties[cProp].dwOptions=DBPROPOPTIONS_REQUIRED; m_DBPropSet.rgProperties[cProp].vValue.vt=VT_BOOL; m_DBPropSet.rgProperties[cProp].colid=DB_NULLID; V_BOOL(&m_DBPropSet.rgProperties[cProp].vValue)=VARIANT_TRUE; m_DBPropSet.rgProperties[cProp+1].dwPropertyID=DBPROP_UPDATABILITY; m_DBPropSet.rgProperties[cProp+1].dwOptions=DBPROPOPTIONS_REQUIRED; if(SettableProperty(DBPROP_UPDATABILITY, DBPROPSET_ROWSET, g_pIDBCreateSession)) m_DBPropSet.rgProperties[cProp+1].vValue.vt=VT_I4; else m_DBPropSet.rgProperties[cProp+1].vValue.vt=VT_EMPTY; m_DBPropSet.rgProperties[cProp+1].colid=DB_NULLID; m_DBPropSet.rgProperties[cProp+1].vValue.lVal=DBPROPVAL_UP_DELETE|DBPROPVAL_UP_CHANGE|DBPROPVAL_UP_INSERT; rgGuid[cProp]=DBPROP_IRowsetChange; rgGuid[cProp+1]=DBPROP_UPDATABILITY; cProp++; cProp++; } rgGuid[0]=DBPROP_IRowsetIdentity; rgGuid[1]=DBPROP_CANHOLDROWS; g_fTestValid = TRUE; //loop throuh all the requested properties for the rowset for (j=0;jGetProperties(1,&DBPropIDSet,&cProperty,&pDBPropSet); if(V_BOOL(&pDBPropSet->rgProperties->vValue)==VARIANT_TRUE&&hr==S_OK) g_fLITERALIDENITIY =TRUE; else g_fLITERALIDENITIY =FALSE; FreeProperties(&cProperty,&pDBPropSet); //initialize DBPROP_REMOVEDELETED DBPropID = DBPROP_REMOVEDELETED; DBPropIDSet.guidPropertySet=DBPROPSET_PROVIDERROWSET; DBPropIDSet.cPropertyIDs=1; DBPropIDSet.rgPropertyIDs=&DBPropID; //ask for in Prop hr = pIRowsetInfo->GetProperties(1,&DBPropIDSet,&cProperty,&pDBPropSet); if(V_BOOL(&pDBPropSet->rgProperties->vValue)==VARIANT_TRUE&&hr==S_OK) g_fREMOVEDELETED =TRUE; else g_fREMOVEDELETED =FALSE; FreeProperties(&cProperty,&pDBPropSet); SAFE_RELEASE(pIRowsetInfo); SAFE_RELEASE(pIRowsetIdentity); //clean up CleanUpTransaction(S_OK); return TRUE; } // {{ TCW_VAR_PROTOTYPE(1) //*----------------------------------------------------------------------- // @mfunc Commit with Retaining. Test on two identical hrows. S_OK or E_UNEXPECTED // // @rdesc TEST_PASS or TEST_FAIL // int Transaction::Variation_1() { IRowsetIdentity *pIRowsetIdentity = NULL; HROW *pHRowThis = NULL; HROW *pHRowThat = NULL; DBCOUNTITEM cRowsThis = 0; DBCOUNTITEM cRowsThat = 0; BOOL fTestPass = FALSE; HRESULT hr = S_OK; if (!m_fTrans) { odtLog << L"The Provider does not support Transactions.\n"; return TRUE; } //if this test variation is not valid if (!g_fTestValid) { odtLog << L"The Provider does not support the properties that are necessary for this variation to execute.\n"; return TEST_PASS; } //start a transaction. Create a rowset with IRowsetIdentity pointer. if(!StartTransaction(SELECT_ORDERBYNUMERIC,(IUnknown **)&pIRowsetIdentity, 1, &m_DBPropSet)) goto END; //get a row handle if(!CHECK(m_pIRowset->GetNextRows(NULL,3,1,&cRowsThis, &pHRowThis),S_OK)) goto END; //commit the transaction with fRetaining==TRUE if(!GetCommit(TRUE)) goto END; //if DBPROP_COMMITPRESERVE is VARIANT_FALSE, the row is in //zomibe state if(!m_fCommitPreserve) { if(CHECK(pIRowsetIdentity->IsSameRow(*pHRowThis, *pHRowThis),E_UNEXPECTED)) { fTestPass=TRUE; } goto END; } //Restart the position to the begining of the rowset hr = m_pIRowset->RestartPosition(NULL); if (S_OK!=hr && DB_S_COMMANDREEXECUTED!=hr) { goto END; } //get the same row handle if(!CHECK(m_pIRowset->GetNextRows(NULL,3,1,&cRowsThat, &pHRowThat),S_OK)) goto END; if (cRowsThis!=cRowsThat) { goto END; } //IsSameRow should return S_OK if(!CHECK(pIRowsetIdentity->IsSameRow(*pHRowThis, *pHRowThat),S_OK)) { goto END; } //binary comparision if(CompareHandlesByLiteral(*pHRowThis,*pHRowThat,FALSE,TRUE,g_fLITERALIDENITIY,g_fSTRONGIDENTITY)) { fTestPass=TRUE; } END: if(pHRowThis) { CHECK(m_pIRowset->ReleaseRows(1,pHRowThis,NULL,NULL,NULL),S_OK); PROVIDER_FREE(pHRowThis); } if(pHRowThat) { CHECK(m_pIRowset->ReleaseRows(1,pHRowThat,NULL,NULL,NULL),S_OK); PROVIDER_FREE(pHRowThat); } SAFE_RELEASE(pIRowsetIdentity); //clean up CleanUpTransaction(S_OK); if(fTestPass) return TEST_PASS; else return TEST_FAIL; } // }} // {{ TCW_VAR_PROTOTYPE(2) //*----------------------------------------------------------------------- // @mfunc Commit without Retaining. Test on two different hrows. S_FALSE or E_UNEXPECTED. // // @rdesc TEST_PASS or TEST_FAIL // int Transaction::Variation_2() { IRowsetIdentity *pIRowsetIdentity = NULL; HROW *pHRowThis = NULL; HROW *pHRowThat = NULL; DBCOUNTITEM cRows = 0; BOOL fTestPass = FALSE; if (!m_fTrans) { odtLog << L"The Provider does not support Transactions.\n"; return TRUE; } //if this test variation is not valid if (!g_fTestValid) { odtLog << L"The Provider does not support the properties that are necessary for this variation to execute.\n"; return TEST_PASS; } //start a transaction. Create a rowset with IRowsetIdentity pointer. if(!StartTransaction(SELECT_ORDERBYNUMERIC, (IUnknown **)&pIRowsetIdentity,1, &m_DBPropSet)) goto END; //get a row handle if(!CHECK(m_pIRowset->GetNextRows(NULL,3,1,&cRows, &pHRowThis),S_OK)) goto END; //commit the transaction with fRetaining==FALSE if(!GetCommit(FALSE)) goto END; //if DBPROP_COMMITPRESERVE is VARIANT_FALSE, the row is in //zomibe state if(!m_fCommitPreserve) { if(CHECK(pIRowsetIdentity->IsSameRow(*pHRowThis, *pHRowThis),E_UNEXPECTED)) { fTestPass=TRUE; } goto END; } //get a different row handle if(!CHECK(m_pIRowset->GetNextRows(NULL,0,1,&cRows, &pHRowThat),S_OK)) goto END; //IsSameRow should return S_FALSE if(!CHECK(pIRowsetIdentity->IsSameRow(*pHRowThis, *pHRowThat),S_FALSE)) { goto END; } //binary comparision if(CompareHandlesByLiteral(*pHRowThis,*pHRowThat,FALSE,FALSE,g_fLITERALIDENITIY,g_fSTRONGIDENTITY)) { fTestPass=TRUE; } END: if(pHRowThis) { CHECK(m_pIRowset->ReleaseRows(1,pHRowThis,NULL,NULL,NULL),S_OK); PROVIDER_FREE(pHRowThis); } if(pHRowThat) { CHECK(m_pIRowset->ReleaseRows(1,pHRowThat,NULL,NULL,NULL),S_OK); PROVIDER_FREE(pHRowThat); } SAFE_RELEASE(pIRowsetIdentity); //clean up CleanUpTransaction(XACT_E_NOTRANSACTION); if(fTestPass) return TEST_PASS; else return TEST_FAIL; } // }} // {{ TCW_VAR_PROTOTYPE(3) //*----------------------------------------------------------------------- // @mfunc Abort with Retaining. Test on one hard deleted row handle and one row handle. // DB_E_DELETEDROW or E_UNEXPECTED. // // @rdesc TEST_PASS or TEST_FAIL // int Transaction::Variation_3() { IRowsetIdentity *pIRowsetIdentity = NULL; IRowsetChange *pIRowsetChange = NULL; HROW *pHRowThis = NULL; HROW *pHRowThat = NULL; DBCOUNTITEM cRowsThis = 0; DBCOUNTITEM cRowsThat = 0; BOOL fTestPass = FALSE; HRESULT hr = S_OK; if (!m_fTrans) { odtLog << L"The Provider does not support Transactions.\n"; return TRUE; } //if IRowsetChange not available because conformance won't allow it if (!g_fIRowsetChange) { odtLog << L"Can not get to IRowsetChange, can not insert a row.\n"; return TEST_PASS; } //if IRowsetChange not available because conformance won't allow it //For read only provider or IRowsetChange not available, skip this variation if(g_fReadOnlyProvider || !(g_fROWSETUPDATABLE)) { odtLog << L"Can not get to IRowsetChange, can not insert a row.\n"; return TEST_PASS; } //if this test variation is not valid if (!g_fTestValid) { odtLog << L"The Provider does not support the properties that are necessary for this variation to execute.\n"; return TEST_PASS; } //start a transaction. Create a rowset with IRowsetIdentity pointer. if(!StartTransaction(SELECT_ORDERBYNUMERIC, (IUnknown **)&pIRowsetIdentity, 1, &m_DBPropSet)) goto END; //QI for IRowsetDelete pointer if(!VerifyInterface(pIRowsetIdentity, IID_IRowsetChange, ROWSET_INTERFACE, (IUnknown**)&pIRowsetChange)) { } //get a row handle if(!CHECK(m_pIRowset->GetNextRows(NULL,3,1,&cRowsThis, &pHRowThis),S_OK)) goto END; //delete the row if(!CHECK(pIRowsetChange->DeleteRows(NULL,1,pHRowThis,NULL),S_OK)) goto END; //abort the transaction with fRetaining==TRUE if(!GetAbort(TRUE)) goto END; //if DBPROP_ABORTPRESERVE is VARIANT_FALSE, the row is in //zomibe state if(!m_fAbortPreserve) { if(CHECK(pIRowsetIdentity->IsSameRow(*pHRowThis, *pHRowThis),E_UNEXPECTED)) { fTestPass=TRUE; } goto END; } //restart the position hr = m_pIRowset->RestartPosition(NULL); if (S_OK!=hr && DB_S_COMMANDREEXECUTED!=hr) { goto END; } //get the same row handle if(!CHECK(m_pIRowset->GetNextRows(NULL,3,1,&cRowsThat, &pHRowThat),S_OK)) goto END; if (cRowsThis!=cRowsThat) { goto END; } //IsSameRow should return S_OK, delete aborted if(!CHECK(pIRowsetIdentity->IsSameRow(*pHRowThis, *pHRowThat),S_OK)) { goto END; } //binary comparision if(CompareHandlesByLiteral(*pHRowThis,*pHRowThat,FALSE,TRUE,g_fLITERALIDENITIY,g_fSTRONGIDENTITY)) { fTestPass=TRUE; } END: if(pHRowThis) { CHECK(m_pIRowset->ReleaseRows(1,pHRowThis,NULL,NULL,NULL),S_OK); PROVIDER_FREE(pHRowThis); } if(pHRowThat) { CHECK(m_pIRowset->ReleaseRows(1,pHRowThat,NULL,NULL,NULL),S_OK); PROVIDER_FREE(pHRowThat); } SAFE_RELEASE(pIRowsetChange); SAFE_RELEASE(pIRowsetIdentity); //clean up CleanUpTransaction(S_OK); if(fTestPass) return TEST_PASS; else return TEST_FAIL; } // }} // {{ TCW_VAR_PROTOTYPE(4) //*----------------------------------------------------------------------- // @mfunc Abort without Retaining. Test on one changed row handle and one row handle that refers to the same row. S_OK or E_UNEXPECTE // // @rdesc TEST_PASS or TEST_FAIL // int Transaction::Variation_4() { IRowsetIdentity *pIRowsetIdentity = NULL; IRowsetChange *pIRowsetChange = NULL; HROW *pHRowThis = NULL; HROW *pHRowThat = NULL; DBCOUNTITEM cRows = 0; BOOL fTestPass = FALSE; if (!m_fTrans) { odtLog << L"The Provider does not support Transactions.\n"; return TRUE; } //if IRowsetChange not available because conformance won't allow it if (!g_fIRowsetChange) { odtLog << L"Can not get to IRowsetChange, can not delete a row.\n"; return TEST_PASS; } //if IRowsetChange not available because conformance won't allow it //For read only provider or IRowsetChange not available, skip this variation if(g_fReadOnlyProvider || !(g_fROWSETUPDATABLE)) { odtLog << L"Can not get to IRowsetChange, can not delete a row.\n"; return TEST_PASS; } //if this test variation is not valid if (!g_fTestValid) { odtLog << L"The Provider does not support the properties that are necessary for this variation to execute.\n"; return TEST_PASS; } //start a transaction. Create a rowset with IRowsetIdentity pointer. if(!StartTransaction(SELECT_ORDERBYNUMERIC, (IUnknown **)&pIRowsetIdentity, 1, &m_DBPropSet)) goto END; //QI for IRowsetDelete pointer if(!VerifyInterface(pIRowsetIdentity, IID_IRowsetChange, ROWSET_INTERFACE, (IUnknown**)&pIRowsetChange)) { goto END; } //get a row handle if(!CHECK(m_pIRowset->GetNextRows(NULL,3,1,&cRows, &pHRowThis),S_OK)) goto END; //abort the transaction with fRetaining==FALSE if(!GetAbort(FALSE)) goto END; //if DBPROP_ABORTPRESERVE is VARIANT_FALSE, the row is in //zomibe state if(!m_fAbortPreserve) { if(CHECK(pIRowsetIdentity->IsSameRow(*pHRowThis, *pHRowThis),E_UNEXPECTED)) { fTestPass=TRUE; } goto END; } //get the row handle if(!CHECK(m_pIRowset->GetNextRows(NULL,3,1,&cRows, &pHRowThat),S_OK)) goto END; //delete the row if(!CHECK(pIRowsetChange->DeleteRows(NULL,1,pHRowThat,NULL),S_OK)) goto END; if(g_fREMOVEDELETED) { //IsSameRow should return S_FALSE if(!CHECK(pIRowsetIdentity->IsSameRow(*pHRowThis, *pHRowThat),S_FALSE)) { goto END; } } else { //IsSameRow should return DB_E_DELETEDROW if(!CHECK(pIRowsetIdentity->IsSameRow(*pHRowThis, *pHRowThat),DB_E_DELETEDROW)) { goto END; } } //binary comparision if(CompareHandlesByLiteral(*pHRowThis, *pHRowThat,FALSE,FALSE,g_fLITERALIDENITIY,g_fSTRONGIDENTITY)) { fTestPass=TRUE; } END: if(pHRowThis) { CHECK(m_pIRowset->ReleaseRows(1,pHRowThis,NULL,NULL,NULL),S_OK); PROVIDER_FREE(pHRowThis); } if(pHRowThat) { CHECK(m_pIRowset->ReleaseRows(1,pHRowThat,NULL,NULL,NULL),S_OK); PROVIDER_FREE(pHRowThat); } SAFE_RELEASE(pIRowsetChange); SAFE_RELEASE(pIRowsetIdentity); //clean up CleanUpTransaction(XACT_E_NOTRANSACTION); if(fTestPass) return TEST_PASS; else return TEST_FAIL; } // }} // {{ TCW_TERMINATE_METHOD //-------------------------------------------------------------------- // @mfunc TestCase Termination Routine // // @rdesc TRUE or FALSE // BOOL Transaction::Terminate() { if(m_DBPropSet.rgProperties) PROVIDER_FREE(m_DBPropSet.rgProperties); return(CTransaction::Terminate()); } // }} // }} // {{ TCW_TC_PROTOTYPE(SchemaRowset) //*----------------------------------------------------------------------- //| Test Case: SchemaRowset //| Created: 02/29/98 //*----------------------------------------------------------------------- //-------------------------------------------------------------------- // @mfunc TestCase Initialization Routine // // @rdesc TRUE or FALSE // BOOL SchemaRowset::Init() { DBPROPID rgGuidSet[1]; rgGuidSet[0]=DBPROP_IRowsetIdentity; if (!g_fIDBSchemaRowset) { odtLog << L"IDBSchemaRowset is not supported by Provider." << ENDL; return TRUE; } if(!TCIRowsetIdentity::Init()) return FALSE; //open rowset for IRowsetIdentity & IDBSchemaRowset if(!GetRowsetAndAccessor(USE_OPENROWSET, 1, rgGuidSet,0,NULL,NO_ACCESSOR)) { return FALSE; } return TRUE; } // {{ TCW_VAR_PROTOTYPE(1) //*----------------------------------------------------------------------- // @mfunc SchemaRowset // // @rdesc TEST_PASS or TEST_FAIL // int SchemaRowset::Variation_1() { DBCOUNTITEM cRows = 0; HROW *pHRow = NULL; IRowsetIdentity *pIRowsetIdentity = NULL; IRowset *pIRowset = NULL; BOOL fTestPass = FALSE; if (!g_fIDBSchemaRowset) { return TEST_SKIPPED; } //IRowset if(!VerifyInterface(m_pIAccessor, IID_IRowset, ROWSET_INTERFACE, (IUnknown**)&pIRowset)) { odtLog << L"IRowset is not supported by Provider." << ENDL; } //IRowsetIdentity if(!VerifyInterface(pIRowset, IID_IRowsetIdentity, ROWSET_INTERFACE, (IUnknown**)&pIRowsetIdentity)) { odtLog << L"IRowsetIdentity is not supported by Provider." << ENDL; } //get two row handles if(!CHECK(pIRowset->GetNextRows(NULL,4,2,&cRows, &pHRow),S_OK)) goto END; //IsSameRow should return S_FALSE if(!CHECK(pIRowsetIdentity->IsSameRow(*pHRow, pHRow[1]),S_FALSE)) { goto END; } //binary comparision if(CompareHandlesByLiteral(*pHRow, pHRow[1],FALSE,FALSE)) { fTestPass=TRUE; } END: if(pHRow) { CHECK(pIRowset->ReleaseRows(cRows, pHRow, NULL,NULL,NULL),S_OK); PROVIDER_FREE(pHRow); } SAFE_RELEASE(pIRowsetIdentity); SAFE_RELEASE(pIRowset); if(fTestPass) return TEST_PASS; else return TEST_FAIL; } // }} // {{ TCW_TERMINATE_METHOD //-------------------------------------------------------------------- // @mfunc TestCase Termination Routine // // @rdesc TRUE or FALSE // BOOL SchemaRowset::Terminate() { ReleaseRowsetAndAccessor(); return(TCIRowsetIdentity::Terminate()); } // }} // }} // {{ TCW_TC_PROTOTYPE(Forward_Only_Cursor) //*----------------------------------------------------------------------- //| Test Case: Forward_Only_Cursor - Forward_Only_Cursor //| Created: 05/28/96 //*----------------------------------------------------------------------- //-------------------------------------------------------------------- // @mfunc TestCase Initialization Routine // // @rdesc TRUE or FALSE // BOOL Forward_Only_Cursor::Init() { BOOL fResults = TRUE; if(!TCIRowsetIdentity::Init()) { return FALSE; } ReleaseRowsetAndAccessor(); return fResults; } // {{ TCW_VAR_PROTOTYPE(1) //*----------------------------------------------------------------------- // @mfunc Fetch two different rows. S_FALSE. // // @rdesc TEST_PASS or TEST_FAIL // int Forward_Only_Cursor::Variation_1() { DBCOUNTITEM cRows = 0; HROW *pHRow = NULL; BOOL fTestPass = TEST_SKIPPED; DBPROPID rgDBPropIDSet[1]; rgDBPropIDSet[0] = DBPROP_IRowsetIdentity; if(!GetRowsetAndAccessor(USE_OPENROWSET, 1, rgDBPropIDSet,0,NULL,NO_ACCESSOR)) { odtLog << L"The Provider does not support the properties that are necessary for this variation to execute.\n"; goto END; } fTestPass = TEST_FAIL; //get two row handles if(!CHECK(m_pIRowset->GetNextRows(NULL,4,2,&cRows, &pHRow),S_OK)) goto END; //IsSameRow should return S_FALSE if(!CHECK(m_pIRowsetIdentity->IsSameRow(*pHRow, pHRow[1]),S_FALSE)) { goto END; } //binary comparision if(CompareHandlesByLiteral(*pHRow, pHRow[1],FALSE,FALSE)) { fTestPass=TRUE; } END: if(pHRow) { CHECK(m_pIRowset->ReleaseRows(cRows, pHRow, NULL,NULL,NULL),S_OK); PROVIDER_FREE(pHRow); } ReleaseRowsetAndAccessor(); if( fTestPass ) return TEST_PASS; else return TEST_FAIL; } // }} // {{ TCW_VAR_PROTOTYPE(2) //*----------------------------------------------------------------------- // @mfunc multiple rows fetched 2 different times. // // @rdesc TEST_PASS or TEST_FAIL // int Forward_Only_Cursor::Variation_2() { const LONG cRows2Fetch = 3; DBCOUNTITEM cRowsA = 0; DBCOUNTITEM cRowsB = 0; DBCOUNTITEM cRowsTemp = 0; HROW *pHRowA = NULL; HROW *pHRowB = NULL; HROW *pHRowTemp = NULL; BOOL fTestPass = TEST_SKIPPED; DBPROPID rgDBPropIDSet[3]; HRESULT hr = S_OK; UWORD i = 0; rgDBPropIDSet[0] = DBPROP_IRowsetIdentity; rgDBPropIDSet[1] = DBPROP_CANHOLDROWS; rgDBPropIDSet[2] = DBPROP_CANFETCHBACKWARDS; if(!GetRowsetAndAccessor(USE_OPENROWSET,2,rgDBPropIDSet,0,NULL,NO_ACCESSOR)) { odtLog << L"The Provider does not support the properties that are necessary for this variation to execute.\n"; goto END; } fTestPass = TEST_FAIL; //get row handles if(!CHECK(m_pIRowset->GetNextRows(NULL,0,cRows2Fetch,&cRowsA, &pHRowA),S_OK)) { goto END; } //restart the position hr = m_pIRowset->RestartPosition(NULL); if (S_OK!=hr && DB_S_COMMANDREEXECUTED!=hr) { if (DB_E_ROWSNOTRELEASED==hr) { //if CANHOLDROWS is TRUE and RestartPosition returns DB_E_ROWSNOTRELEASED //then check DBPROP_QUICKRESTART. //if DBPROP_QUICKRESTART is FALSE (command re-executed) this could be valid //but if DBPROP_QUICKRESTART is TRUE DB_E_ROWSNOTRELEASED should not be //returned from RestartPosition if CANHOLDROWS is requested if(GetProperty(DBPROP_QUICKRESTART, DBPROPSET_ROWSET, (IUnknown*)m_pIRowset)) { goto END; } else { //can't just do a refresh so drop and recreate the rowset this time //do a fetch backwards here so we still have rowA handles and can compare //release the rows and restart again if(pHRowA) { CHECK(ReleaseRows(cRows2Fetch,&pHRowA,TRUE),S_OK); PROVIDER_FREE(pHRowA); } ReleaseRowsetAndAccessor(); if(!GetRowsetAndAccessor(USE_OPENROWSET,3,rgDBPropIDSet,0,NULL,NO_ACCESSOR)) { odtLog << L"The Provider does not support the properties that are necessary for this variation to execute.\n"; fTestPass = TEST_SKIPPED; goto END; } fTestPass = TEST_FAIL; //get row handles if(!CHECK(m_pIRowset->GetNextRows(NULL,0,cRows2Fetch,&cRowsA, &pHRowA),S_OK)) { goto END; } COMPARE(cRows2Fetch,cRowsA); //move back over row handles if(!CHECK(m_pIRowset->GetNextRows(NULL,0,-cRows2Fetch,&cRowsTemp, &pHRowTemp),S_OK)) { goto END; } COMPARE(cRowsA,cRowsTemp); //get the same row handles if(!CHECK(m_pIRowset->GetNextRows(NULL,0,cRows2Fetch,&cRowsB, &pHRowB),S_OK)) { goto END; } for (i = 0;iIsSameRow(pHRowA[i], pHRowB[i]),S_OK)) { goto END; } //binary comparision if(!CompareHandlesByLiteral(pHRowA[i], pHRowB[i],FALSE,TRUE)) { goto END; } if(!CHECK(m_pIRowsetIdentity->IsSameRow(pHRowA[i], pHRowTemp[(cRows2Fetch-1)-i]),S_OK)) { goto END; } //binary comparision if(!CompareHandlesByLiteral(pHRowA[i], pHRowTemp[(cRows2Fetch-1)-i],FALSE,TRUE)) { goto END; } } fTestPass=TRUE; } goto END; } else { goto END; } } //release the rows and restart again if(pHRowB) { CHECK(ReleaseRows(cRows2Fetch,&pHRowB,TRUE),S_OK); PROVIDER_FREE(pHRowB); } //get the same row handles if(!CHECK(m_pIRowset->GetNextRows(NULL,0,cRows2Fetch,&cRowsB, &pHRowB),S_OK)) { goto END; } for (i = 0;iIsSameRow(pHRowA[i], pHRowB[i]),S_OK)) { goto END; } //binary comparision if(CompareHandlesByLiteral(pHRowA[i], pHRowB[i],FALSE,TRUE)) { fTestPass=TRUE; } } fTestPass=TRUE; END: if (m_pIRowset && pHRowA && pHRowB) { CHECK(m_pIRowset->ReleaseRows(cRowsA, pHRowA, NULL,NULL,NULL),S_OK); PROVIDER_FREE(pHRowA); CHECK(m_pIRowset->ReleaseRows(cRowsB, pHRowB, NULL,NULL,NULL),S_OK); PROVIDER_FREE(pHRowB); CHECK(m_pIRowset->ReleaseRows(cRowsTemp, pHRowTemp, NULL,NULL,NULL),S_OK); PROVIDER_FREE(pHRowTemp); ReleaseRowsetAndAccessor(); } if( fTestPass ) return TEST_PASS; else return TEST_FAIL; } // }} // {{ TCW_VAR_PROTOTYPE(3) //*----------------------------------------------------------------------- // @mfunc REMOVEDELETED FALSE // // @rdesc TEST_PASS or TEST_FAIL // int Forward_Only_Cursor::Variation_3() { const ULONG cRows2Use = 3; DBCOUNTITEM cRowsA = 0; DBCOUNTITEM cRowsB = 0; HROW *pHRowA = NULL; HROW *pHRowB = NULL; BOOL fTestPass = TEST_SKIPPED; DBPROPID rgDBPropIDSet[3]; DBPROPID rgDBPropIDUnSet[1]; HRESULT hr = S_OK; UWORD i = 0; rgDBPropIDSet[0] = DBPROP_IRowsetIdentity; rgDBPropIDSet[1] = DBPROP_IRowsetChange; rgDBPropIDSet[2] = DBPROP_CANHOLDROWS; rgDBPropIDUnSet[0] = DBPROP_REMOVEDELETED; m_ulUpdFlags = DBPROPVAL_UP_DELETE; if(!GetRowsetAndAccessor(USE_OPENROWSET,3,rgDBPropIDSet,1,rgDBPropIDUnSet,NO_ACCESSOR)) { odtLog << L"The Provider does not support the properties that are necessary for this variation to execute.\n"; goto END; } fTestPass = TEST_FAIL; if (!m_pIRowsetChange) { goto END; } //get row handles if(!CHECK(m_pIRowset->GetNextRows(NULL,1,cRows2Use,&cRowsA, &pHRowA),S_OK)) { goto END; } //delete the rows if(!CHECK(m_pIRowsetChange->DeleteRows(NULL,cRows2Use,pHRowA, NULL),S_OK)) { goto END; } //restart the position hr = m_pIRowset->RestartPosition(NULL); if (S_OK!=hr && DB_S_COMMANDREEXECUTED!=hr) { goto END; } //get the same row handles if(!CHECK(m_pIRowset->GetNextRows(NULL,1,cRows2Use,&cRowsB, &pHRowB),S_OK)) goto END; for (i=0;iIsSameRow(pHRowA[i], pHRowB[i]),DB_E_DELETEDROW)) { goto END; } //binary comparision if(!CompareHandlesByLiteral(pHRowA[i], pHRowB[i],FALSE,TRUE)) { goto END; } } fTestPass=TRUE; END: m_ulUpdFlags = DBPROPVAL_UP_CHANGE|DBPROPVAL_UP_DELETE|DBPROPVAL_UP_INSERT; if (m_pIRowset) { CHECK(m_pIRowset->ReleaseRows(cRowsA, pHRowA, NULL,NULL,NULL),S_OK); PROVIDER_FREE(pHRowA); CHECK(m_pIRowset->ReleaseRows(cRowsB, pHRowB, NULL,NULL,NULL),S_OK); PROVIDER_FREE(pHRowB); ReleaseRowsetAndAccessor(); } if( fTestPass ) return TEST_PASS; else return TEST_FAIL; } // }} // {{ TCW_VAR_PROTOTYPE(4) //*----------------------------------------------------------------------- // @mfunc REMOVEDELETED TRUE // // @rdesc TEST_PASS or TEST_FAIL // int Forward_Only_Cursor::Variation_4() { const ULONG cRows2Use = 3; DBCOUNTITEM cRowsA = 0; DBCOUNTITEM cRowsA2 = 0; DBCOUNTITEM cRowsB = 0; HROW *pHRowA = NULL; HROW *pHRowA2 = NULL; HROW *pHRowB = NULL; BOOL fTestPass = TEST_SKIPPED; DBPROPID rgDBPropIDSet[4]; HRESULT hr = S_OK; UWORD i = 0; void *pDataA2 = NULL; void *pDataB = NULL; rgDBPropIDSet[0] = DBPROP_IRowsetIdentity; rgDBPropIDSet[1] = DBPROP_IRowsetChange; rgDBPropIDSet[2] = DBPROP_CANHOLDROWS; rgDBPropIDSet[3] = DBPROP_REMOVEDELETED; if(!GetRowsetAndAccessor(USE_OPENROWSET,4,rgDBPropIDSet,0,NULL,ON_ROWSET_ACCESSOR)) { odtLog << L"The Provider does not support the properties that are necessary for this variation to execute.\n"; goto CLEANUP; } QTESTC(m_pIRowsetChange != NULL); fTestPass = TEST_FAIL; //get row handles TESTC_(m_pIRowset->GetNextRows(NULL,0,cRows2Use,&cRowsA, &pHRowA),S_OK); //get next set of row handles TESTC_(m_pIRowset->GetNextRows(NULL,0,cRows2Use,&cRowsA2, &pHRowA2),S_OK); //delete the rows TESTC_(m_pIRowsetChange->DeleteRows(NULL,cRows2Use,pHRowA, NULL),S_OK); //restart the position hr = m_pIRowset->RestartPosition(NULL); TEST2C_(hr, S_OK, DB_S_COMMANDREEXECUTED); //get the same row handles TESTC_(m_pIRowset->GetNextRows(NULL,0,cRows2Use,&cRowsB, &pHRowB),S_OK); for (i=0; i < cRows2Use; i++) { //IsSameRow pHRowA and pHRowB //should return DB_E_DELETEDROW because pHRowA can only point to is deleted rows TESTC_(m_pIRowsetIdentity->IsSameRow(pHRowA[i], pHRowB[i]),DB_E_DELETEDROW); TESTC(CompareHandlesByLiteral(pHRowA[i], pHRowB[i],FALSE,FALSE)); //IsSameRow pHRowA2 and pHRowB //should return S_OK TESTC_(m_pIRowsetIdentity->IsSameRow(pHRowA2[i], pHRowB[i]),S_OK); TESTC(CompareHandlesByLiteral(pHRowA2[i], pHRowB[i],FALSE,TRUE)); //allocate the data pDataA2 = PROVIDER_ALLOC(m_cRowSize); TESTC(pDataA2 != NULL); pDataB = PROVIDER_ALLOC(m_cRowSize); TESTC(pDataB != NULL); //get the data TESTC_(m_pIRowset->GetData(pHRowA2[i], m_hAccessor, pDataA2),S_OK); //get the data TESTC_(m_pIRowset->GetData(pHRowB[i], m_hAccessor, pDataB),S_OK); //compare the buffer TESTC(CompareBuffer(pDataA2,pDataB,m_cBinding,m_rgBinding,m_pIMalloc,TRUE,FALSE,COMPARE_FREE)); //free the memory PROVIDER_FREE(pDataA2); PROVIDER_FREE(pDataB); } fTestPass=TRUE; CLEANUP: if( m_pIRowset ) { CHECK(m_pIRowset->ReleaseRows(cRowsA, pHRowA, NULL,NULL,NULL),S_OK); PROVIDER_FREE(pHRowA); CHECK(m_pIRowset->ReleaseRows(cRowsA2, pHRowA2, NULL,NULL,NULL),S_OK); PROVIDER_FREE(pHRowA2); CHECK(m_pIRowset->ReleaseRows(cRowsB, pHRowB, NULL,NULL,NULL),S_OK); PROVIDER_FREE(pHRowB); ReleaseRowsetAndAccessor(); } //free the memory PROVIDER_FREE(pDataA2); PROVIDER_FREE(pDataB); if( fTestPass ) return TEST_PASS; else return TEST_FAIL; } // }} // {{ TCW_VAR_PROTOTYPE(5) //*----------------------------------------------------------------------- // @mfunc QI without DBPROP_IRowsetIdentity requested // // @rdesc TEST_PASS or TEST_FAIL // int Forward_Only_Cursor::Variation_5() { IRowset *pIRowset = NULL; IRowsetIdentity *pIRowsetIdentity = NULL; DBCOUNTITEM cRows = 0; HROW *pHRow = NULL; HRESULT hr; BOOL fTestPass = TEST_SKIPPED; DBPROPSET rgDBPropSet[1] = {NULL}; //IOpenRowset to return a Rowset from table g_pCTable->CreateRowset ( USE_OPENROWSET, IID_IRowset, 0, NULL, (IUnknown**)&pIRowset, NULL, NULL, NULL ); //Get a row handle if(!CHECK(pIRowset->GetNextRows(NULL,0,1,&cRows, &pHRow),S_OK)) { goto END; } fTestPass = TEST_FAIL; //get the IRowsetIdentity pointer without requesting the DBPROP_IRowsetIdentity prop hr = pIRowset->QueryInterface(IID_IRowsetIdentity, (void**)&pIRowsetIdentity); //if this succeeded test the interface if (S_OK==hr) { if(!CHECK(pIRowsetIdentity->IsSameRow(*pHRow,*pHRow),S_OK)) { goto END; } fTestPass = TRUE; } //if it failed make sure gettting the interface is possible if (E_NOINTERFACE==hr) { //init DBPropSet[0] rgDBPropSet[0].rgProperties =NULL; rgDBPropSet[0].guidPropertySet =DBPROPSET_ROWSET; rgDBPropSet[0].cProperties =1; //allocate rgDBPropSet[0].rgProperties=(DBPROP *)PROVIDER_ALLOC(sizeof(DBPROP)*(rgDBPropSet[0].cProperties)); if (!rgDBPropSet[0].rgProperties) { goto END; } memset(rgDBPropSet[0].rgProperties,0xCA,(rgDBPropSet[0].cProperties)*sizeof(DBPROP)); rgDBPropSet[0].rgProperties[0].dwPropertyID=DBPROP_IRowsetIdentity; rgDBPropSet[0].rgProperties[0].dwOptions=DBPROPOPTIONS_REQUIRED; rgDBPropSet[0].rgProperties[0].vValue.vt=VT_BOOL; rgDBPropSet[0].rgProperties[0].colid=DB_NULLID; V_BOOL(&rgDBPropSet[0].rgProperties[0].vValue)=VARIANT_TRUE; if(pHRow) { pIRowset->ReleaseRows(cRows, pHRow, NULL,NULL, NULL); } // Release interface pointer SAFE_RELEASE(pIRowset); //IOpenRowset to return a Rowset from table g_pCTable->CreateRowset ( USE_OPENROWSET, IID_IRowset, 1, rgDBPropSet, (IUnknown**)&pIRowset, NULL, NULL, NULL ); //Get a row handle if(!CHECK(pIRowset->GetNextRows(NULL,0,1,&cRows, &pHRow),S_OK)) { goto END; } //get the IRowsetIdentity pointer without requesting the DBPROP_IRowsetIdentity prop if(!CHECK(pIRowset->QueryInterface(IID_IRowsetIdentity, (void**)&pIRowsetIdentity),S_OK)) { goto END; } if(!CHECK(pIRowsetIdentity->IsSameRow(*pHRow,*pHRow),S_OK)) { goto END; } fTestPass = TRUE; } END: PROVIDER_FREE(rgDBPropSet[0].rgProperties); if(pHRow) { pIRowset->ReleaseRows(cRows, pHRow, NULL,NULL, NULL); } // Release interface pointers SAFE_RELEASE(pIRowset); SAFE_RELEASE(pIRowsetIdentity); if( fTestPass ) return TEST_PASS; else return TEST_FAIL; } // }} // {{ TCW_TERMINATE_METHOD //-------------------------------------------------------------------- // @mfunc TestCase Termination Routine // // @rdesc TRUE or FALSE // BOOL Forward_Only_Cursor::Terminate() { ReleaseRowsetAndAccessor(); return(TCIRowsetIdentity::Terminate()); } // }} // }} // {{ TCW_TC_PROTOTYPE(Static_Query_Immediate) //*----------------------------------------------------------------------- //| Test Case: Static_Query_Immediate - Static_Query_Immediate //| Created: 05/28/96 //*----------------------------------------------------------------------- //-------------------------------------------------------------------- // @mfunc TestCase Initialization Routine // // @rdesc TRUE or FALSE // BOOL Static_Query_Immediate::Init() { DBPROPID rgGuid[5]; DBPROPID rgGuidUnset[2]; BOOL fCursorNotSupported=FALSE; ULONG cProp=0; ULONG cPropUnset=0; rgGuidUnset[0]=DBPROP_OTHERUPDATEDELETE; rgGuidUnset[1]=DBPROP_OTHERINSERT; cPropUnset=2; rgGuid[0]=DBPROP_IRowsetIdentity; rgGuid[1]=DBPROP_CANSCROLLBACKWARDS; rgGuid[2]=DBPROP_CANHOLDROWS; rgGuid[3]=DBPROP_IRowsetChange; rgGuid[4]=KAGPROP_QUERYBASEDUPDATES; //if this is kagera then count the KAGPROP above as a property cProp=g_MSDASQL?5:4; if(!TCIRowsetIdentity::Init()) return FALSE; //check to see if the execute is going to fail if( !g_rgDBPrpt[IDX_ScrollBackwards].fSupported || !g_rgDBPrpt[IDX_CanHoldRows].fSupported || !g_rgDBPrpt[IDX_FetchBackwards].fSupported ) { fCursorNotSupported = TRUE; odtLog << L"The Provider does not support a STATIC Cursor.\n"; } //get a rowset with IRowsetIdentity, with Static Cursor if(!GetRowsetAndAccessor(USE_OPENROWSET, cProp, rgGuid,cPropUnset,rgGuidUnset,NO_ACCESSOR)) { return TEST_SKIPPED; } if (!g_fTestValid) { return TRUE; } //has to be static cursor if(GetCursorType()==STATIC_CURSOR) { odtLog << L"This test will continue but a static cursor was not obtained.\n"; // return FALSE; } return TRUE; } // {{ TCW_VAR_PROTOTYPE(1) //*----------------------------------------------------------------------- // @mfunc Fetch one row. Move the cursor and fetch backwards to retrieve the same row handle. S_OK. // // @rdesc TEST_PASS or TEST_FAIL // int Static_Query_Immediate::Variation_1() { HROW rgHrow[3]; HROW *pHRow = rgHrow; DBCOUNTITEM cRows = 0; ULONG cRowCount = 0; BOOL fTestPass = FALSE; //Get a row handle if(!CHECK(m_pIRowset->GetNextRows(NULL,8,1,&cRows, &pHRow),S_OK)) goto END; cRowCount++; //move the cursor away pHRow=&(rgHrow[1]); if(!CHECK(m_pIRowset->GetNextRows(NULL,0,1,&cRows, &pHRow),S_OK)) goto END; cRowCount++; //get the first row handle again pHRow=&(rgHrow[2]); if(!CHECK(m_pIRowset->GetNextRows(NULL,-2,1,&cRows, &pHRow),S_OK)) goto END; cRowCount++; //IsSameRow should return S_OK. if(!CHECK(m_hr=m_pIRowsetIdentity->IsSameRow(rgHrow[0], rgHrow[2]),S_OK)) { goto END; } //binary comparision if(CompareHandlesByLiteral(rgHrow[0], rgHrow[2],FALSE,TRUE)) { fTestPass=TRUE; } END: CHECK(m_pIRowset->ReleaseRows(cRowCount, rgHrow, NULL,NULL, NULL),S_OK); if(fTestPass) return TEST_PASS; else return TEST_FAIL; } // }} // {{ TCW_VAR_PROTOTYPE(2) //*----------------------------------------------------------------------- // @mfunc Hard deleted the 1st row handle. Fetch the same row again. // // @rdesc TEST_PASS or TEST_FAIL // int Static_Query_Immediate::Variation_2() { HROW *pHRow = NULL; HROW *pHRowSecond = NULL; DBCOUNTITEM cRows = 0; BOOL fTestPass = FALSE; DBROWSTATUS *pDBRowStatus = NULL; BOOL fPending = TRUE; //get a row handle if(!CHECK(m_pIRowset->GetNextRows(NULL,1,1,&cRows,&pHRow),S_OK)) goto END; //hard delete the row if(!CHECK(DeleteRows(1,pHRow),S_OK)) goto END; //get the same row again if(!CHECK(m_pIRowset->GetNextRows(NULL,-1,1,&cRows,&pHRowSecond),S_OK)) goto END; //IsSameRow should return DB_E_DELETEDROW if(!CHECK(m_pIRowsetIdentity->IsSameRow(*pHRow, *pHRowSecond),DB_E_DELETEDROW)) { goto END; } //binary comparision if(!CompareHandlesByLiteral(*pHRow, *pHRowSecond,FALSE,TRUE)) { goto END; } if (g_fREMOVEDELETED) { //IsSameRow should return S_OK - REMOVEDELETED is TRUE if(!CHECK(m_pIRowsetIdentity->IsSameRow(*pHRowSecond, *pHRowSecond),S_OK)) { goto END; } //binary comparision if(!CompareHandlesByLiteral(*pHRowSecond, *pHRowSecond,FALSE,TRUE)) { goto END; } } else { //IsSameRow should return DB_E_DELETEDROW REMOVEDELETED is FALSE if(!CHECK(m_pIRowsetIdentity->IsSameRow(*pHRowSecond, *pHRowSecond),DB_E_DELETEDROW)) { goto END; } //binary comparision - because a handle to a deleted row should compare with itself if(!CompareHandlesByLiteral(*pHRowSecond, *pHRowSecond,FALSE,TRUE)) { goto END; } } fTestPass=TRUE; END: //undo the deletions if(pHRow) { CHECK(ReleaseRows(1, &pHRow,TRUE),S_OK); } if(pHRowSecond) CHECK(ReleaseRows(1, &pHRowSecond,TRUE),S_OK); if(pDBRowStatus) PROVIDER_FREE(pDBRowStatus); if(fTestPass) return TEST_PASS; else return TEST_FAIL; } // }} // {{ TCW_TERMINATE_METHOD //-------------------------------------------------------------------- // @mfunc TestCase Termination Routine // // @rdesc TRUE or FALSE // BOOL Static_Query_Immediate::Terminate() { ReleaseRowsetAndAccessor(); // {{ TCW_TERM_BASECLASS_CHECK2 return(TCIRowsetIdentity::Terminate()); } // }} // }} // {{ TCW_TC_PROTOTYPE(Static_Cursor_Buffered) //*----------------------------------------------------------------------- //| Test Case: Static_Cursor_Buffered - Static_Cursor_Buffered //| Created: 05/28/96 //*----------------------------------------------------------------------- //-------------------------------------------------------------------- // @mfunc TestCase Initialization Routine // // @rdesc TRUE or FALSE // BOOL Static_Cursor_Buffered::Init() { DBPROPID rgGuid[5]; DBPROPID rgGuidUnset[2]; BOOL fCursorNotSupported = FALSE; ULONG cProp = 0; ULONG cPropUnset = 0; rgGuidUnset[0]=DBPROP_OTHERUPDATEDELETE; rgGuidUnset[1]=DBPROP_OTHERINSERT; cPropUnset=2; rgGuid[0]=DBPROP_IRowsetIdentity; rgGuid[1]=DBPROP_CANSCROLLBACKWARDS; rgGuid[2]=DBPROP_CANHOLDROWS; rgGuid[3]=DBPROP_IRowsetUpdate; rgGuid[4]=DBPROP_IRowsetChange; cProp=5; if(!TCIRowsetIdentity::Init()) return FALSE; //check to see if the execute is going to fail if( !g_rgDBPrpt[IDX_ScrollBackwards].fSupported) { fCursorNotSupported = TRUE; odtLog << L"The Provider does not support a STATIC Cursor.\n"; } //get a rowset with IRowsetIdentity, with Static Cursor if(!GetRowsetAndAccessor(USE_OPENROWSET, cProp, rgGuid,cPropUnset,rgGuidUnset,ON_ROWSET_ACCESSOR)) { return TEST_SKIPPED; } if (!g_fTestValid) { return TRUE; } //has to be static cursor if(!COMPARE(GetCursorType()==STATIC_CURSOR, TRUE)) { return FALSE; } return TRUE; } // {{ TCW_VAR_PROTOTYPE(1) //*----------------------------------------------------------------------- // @mfunc Soft deleted the 1st row handle. // // @rdesc TEST_PASS or TEST_FAIL // int Static_Cursor_Buffered::Variation_1() { HROW *pHRow0 = NULL; HROW *pHRow1 = NULL; HROW *pHRow2 = NULL; HROW *pHRow1AfterDel = NULL; DBCOUNTITEM cRows = 0; BOOL fTestPass = FALSE; DBROWSTATUS *pDBRowStatus = NULL; BOOL fPending = TRUE; void *pData1 = NULL; void *pData2 = NULL; if(!(pData1=(BYTE*)PROVIDER_ALLOC(m_cRowSize))) goto END; if(!(pData2=(BYTE*)PROVIDER_ALLOC(m_cRowSize))) goto END; //get a row handle if(!CHECK(m_pIRowset->GetNextRows(NULL,0,1,&cRows,&pHRow0),S_OK)) goto END; //get the next row handle if(!CHECK(m_pIRowset->GetNextRows(NULL,0,1,&cRows,&pHRow1),S_OK)) goto END; //get the data for the row if(!CHECK(m_pIRowset->GetData(*pHRow1, m_hAccessor, pData1),S_OK)) goto END; //get the next row handle if(!CHECK(m_pIRowset->GetNextRows(NULL,0,1,&cRows,&pHRow2),S_OK)) goto END; //soft delete the 2nd row if(!CHECK(DeleteRows(1,pHRow1),S_OK)) goto END; //try to get the 2nd row again, pending delete might or might not be there //if it is there this will fetch it, if it is not there this will fetch the first row if(!CHECK(m_pIRowset->GetNextRows(NULL,-2,1,&cRows,&pHRow1AfterDel),S_OK)) goto END; //determine through props which row was fetched and check it //if test doesn't see its own deletes the first row should have been fetched if (!g_fOWNUPDATEDELETE) { //IsSameRow should return S_OK. if(!CHECK(m_pIRowsetIdentity->IsSameRow(*pHRow1, *pHRow1AfterDel),S_OK)) { goto END; } //binary comparision, if(!CompareHandlesByLiteral(*pHRow1, *pHRow1AfterDel,FALSE,TRUE)) { goto END; } //so look at buffer just for fun if(!CHECK(m_pIRowset->GetData(*pHRow1AfterDel, m_hAccessor, pData2),S_OK)) goto END; //since OWNUPDATEDELETE is FALSE these do compare, delete is not seen if(!CompareBuffer(pData1,pData2,m_cBinding,m_rgBinding,m_pIMalloc,TRUE,FALSE,COMPARE_ONLY)==TRUE) { goto END; } } else { if (g_fLITERALIDENITIY&&g_fREMOVEDELETED) { //IsSameRow should return S_FALSE. if(!CHECK(m_pIRowsetIdentity->IsSameRow(*pHRow1, *pHRow1AfterDel),S_FALSE)) { goto END; } //binary comparision, if(!CompareHandlesByLiteral(*pHRow1, *pHRow1AfterDel,FALSE,FALSE)) { goto END; } //IsSameRow should return S_OK first row fetched and new fetch because the deleted row is removed if(!CHECK(m_pIRowsetIdentity->IsSameRow(*pHRow0, *pHRow1AfterDel),S_OK)) { goto END; } //binary comparision, these rows can compare literally if(!CompareHandlesByLiteral(*pHRow0, *pHRow1AfterDel,FALSE,TRUE)) { goto END; } } else { //IsSameRow should return DB_E_DELETEDROW the deleted row is not removed which is //pointed to by pHRow1AfterDel //IsSameRow should return S_OK. if(!CHECK(m_pIRowsetIdentity->IsSameRow(*pHRow1, *pHRow1AfterDel),S_OK)) { goto END; } //binary comparision, if(!CompareHandlesByLiteral(*pHRow1, *pHRow1AfterDel,FALSE,TRUE)) { goto END; } } } //Update the data, deletes are no longer pending if(!CHECK(UpdateRows(1,pHRow1,&pDBRowStatus),S_OK)) goto END; //IsSameRow should return DB_E_DELETEDROW because pHRow1 points to a deleted //row no matter what DBPROP_REMOVEDELETED has for a default if(!CHECK(m_pIRowsetIdentity->IsSameRow(*pHRow1, *pHRow1AfterDel),DB_E_DELETEDROW)) { goto END; } if (g_fREMOVEDELETED) { //binary comparision if(!CompareHandlesByLiteral(*pHRow1, *pHRow1AfterDel,FALSE,FALSE)) { goto END; } //IsSameRow should return S_OK because the deleted row is removed if(!CHECK(m_pIRowsetIdentity->IsSameRow(*pHRow0, *pHRow1AfterDel),S_OK)) { goto END; } //binary comparision, these rows can compare literally if(!CompareHandlesByLiteral(*pHRow0, *pHRow1AfterDel,FALSE,TRUE)) { goto END; } } else { //binary comparision if(!CompareHandlesByLiteral(*pHRow1, *pHRow1AfterDel,FALSE,TRUE)) { goto END; } //IsSameRow should return DB_E_DELETEDROW the deleted row is not removed which is //pointed to by pHRow1AfterDel if(!CHECK(m_pIRowsetIdentity->IsSameRow(*pHRow0, *pHRow1AfterDel),DB_E_DELETEDROW)) { goto END; } //binary comparision if(!CompareHandlesByLiteral(*pHRow0, *pHRow1AfterDel,FALSE,FALSE)) { goto END; } } fTestPass = TRUE; END: //undo the deletions if(pHRow0) { CHECK(ReleaseRows(1, &pHRow0,TRUE),S_OK); } //undo the deletions if(pHRow1) { CHECK(ReleaseRows(1, &pHRow1,TRUE),S_OK); } //undo the deletions if(pHRow2) { CHECK(ReleaseRows(1, &pHRow2,TRUE),S_OK); } if(pData1) ReleaseInputBindingsMemory(m_cBinding, m_rgBinding,(BYTE *)pData1,FALSE); if(pData2) ReleaseInputBindingsMemory(m_cBinding, m_rgBinding,(BYTE *)pData2,TRUE); if(pHRow1AfterDel) CHECK(ReleaseRows(1, &pHRow1AfterDel,TRUE),S_OK); if(pDBRowStatus) PROVIDER_FREE(pDBRowStatus); if(fTestPass) return TEST_PASS; else return TEST_FAIL; } // }} // {{ TCW_VAR_PROTOTYPE(2) //*----------------------------------------------------------------------- // @mfunc Fetch hRowThis and soft change the row. The row should stay in place in the rowset. // Fetch the row handle again in hRowThat // // @rdesc TEST_PASS or TEST_FAIL // int Static_Cursor_Buffered::Variation_2() { void *pData1 = NULL; void *pData2 = NULL; HROW *pHRowThis = NULL; HROW *pHRowThat = NULL; DBCOUNTITEM cRows = 0; BOOL fTestPass = FALSE; HRESULT hr; //get an accessor if(!GetAccessorOnRowset(ON_ROWSET_ACCESSOR, DBACCESSOR_ROWDATA, DBPART_VALUE|DBPART_STATUS|DBPART_LENGTH, UPDATEABLE_COLS_BOUND)) goto END; //Restart the position to the begining of the rowset hr = m_pIRowset->RestartPosition(NULL); if (S_OK!=hr && DB_S_COMMANDREEXECUTED!=hr) { goto END; } //get a row handle if(!CHECK(m_pIRowset->GetNextRows(NULL,9,1,&cRows,&pHRowThis),S_OK)) goto END; //get the data for the row if(!CHECK(m_pIRowset->GetData(*pHRowThis, m_hAccessor, m_pData),S_OK)) goto END; //change it if(!CHECK(ChangeOneRow(*pHRowThis, g_ulNextRow++, &pData1),S_OK)) goto END; //get the row handle again if(!CHECK(m_pIRowset->GetNextRows(NULL,-1,1,&cRows,&pHRowThat),S_OK)) goto END; //IsSameRow should return S_OK if(!CHECK(m_pIRowsetIdentity->IsSameRow(*pHRowThis, *pHRowThat),S_OK)) { goto END; } //binary comparision if(!CompareHandlesByLiteral(*pHRowThis, *pHRowThat,FALSE,TRUE)) { goto END; } //will this rowset see its pending changes if (g_fLITERALIDENITIY&&g_fOWNUPDATEDELETE) { //GetData on pHRowThat, should return the updated data buffer if(!COMPARE(CheckExpectedData(*pHRowThat, pData1, TRUE),TRUE)) goto END; } else { //GetData on pHRowThat, should return the first data because //LI is false (pending changes are not seen) //the old buffer should be here if(!COMPARE(CheckExpectedData(*pHRowThat, m_pData, TRUE),TRUE)) goto END; } //change data by pHRowThat if(!CHECK(ChangeOneRow(*pHRowThat, g_ulNextRow++, &pData2),S_OK)) goto END; //this rowset will see its pending change only if DBPROP_LITERALIDENTITY is TRUE AND OWNUPDEL is TRUE //if LI is FALSE pending changes are not seen if (g_fLITERALIDENITIY&&g_fOWNUPDATEDELETE) { if(!COMPARE(CheckExpectedData(*pHRowThis, pData2, TRUE),TRUE)) goto END; } else { if(!COMPARE(CheckExpectedData(*pHRowThis, pData1, TRUE),TRUE)) goto END; } //Undo hRowThat //same rules apply for Undo as for visibility of pending changes //if LI is TRUE test just undid all changes //eles it just undid changes on hRowThat if(!CHECK(UndoRows(1,pHRowThat),S_OK)) goto END; //this rowset will see its pending change only if DBPROP_LITERALIDENTITY is TRUE AND OWNUPDEL is TRUE //if LI is FALSE pending changes are not seen if (g_fLITERALIDENITIY&&g_fOWNUPDATEDELETE) { //GetData on pHRowThis should return its first change if(!COMPARE(CheckExpectedData(*pHRowThis, m_pData, TRUE),TRUE)) goto END; } else { //GetData on pHRowThis should return its first change if(!COMPARE(CheckExpectedData(*pHRowThis, pData1, TRUE),TRUE)) goto END; } //release the one row handle(this) if(pHRowThis) CHECK(ReleaseRows(1,&pHRowThis,TRUE),S_OK); //get the row handle again. if(!CHECK(m_pIRowset->GetNextRows(NULL,-1,1,&cRows,&pHRowThis),S_OK)) goto END; //IsSameRow should return S_OK (the row will always be the row, just the data might be chaged) if(!CHECK(m_pIRowsetIdentity->IsSameRow(*pHRowThis, *pHRowThat),S_OK)) { goto END; } //binary comparision if(!CompareHandlesByLiteral(*pHRowThis, *pHRowThat,FALSE,TRUE)) { goto END; } //this rowset will see its pending change only if DBPROP_LITERALIDENTITY is TRUE AND OWNUPDEL is TRUE //if LI is FALSE pending changes are not seen if (g_fLITERALIDENITIY&&g_fOWNUPDATEDELETE) { //GetData on pHRowThat should return row after undo if(!COMPARE(CheckExpectedData(*pHRowThat, m_pData, TRUE),TRUE)) goto END; } else { //GetData on pHRowThat should return the row's first change if(!COMPARE(CheckExpectedData(*pHRowThat, pData2, TRUE),TRUE)) goto END; } fTestPass=TRUE; END: if(m_pData) ReleaseInputBindingsMemory(m_cBinding, m_rgBinding,(BYTE *)m_pData,FALSE); if(pData1) ReleaseInputBindingsMemory(m_cBinding, m_rgBinding,(BYTE *)pData1,FALSE); if(pData2) ReleaseInputBindingsMemory(m_cBinding, m_rgBinding,(BYTE *)pData2,TRUE); if(pHRowThis) CHECK(ReleaseRows(1,&pHRowThis,TRUE),S_OK); if(pHRowThat) CHECK(ReleaseRows(1,&pHRowThat,TRUE),S_OK); ReleaseAccessorOnRowset(); if(fTestPass) return TEST_PASS; else return TEST_FAIL; } // }} // {{ TCW_VAR_PROTOTYPE(3) //*----------------------------------------------------------------------- // @mfunc Insert a new row. Compare it with a new row handle. // // @rdesc TEST_PASS or TEST_FAIL // int Static_Cursor_Buffered::Variation_3() { HROW HRow = NULL; HROW *pHRow = NULL; DBCOUNTITEM cRows = 0; BYTE *pData = NULL; BOOL fTestPass = FALSE; HRESULT hr; BOOL fFound = FALSE; //Restart the position to the begining of the rowset hr = m_pIRowset->RestartPosition(NULL); if (S_OK!=hr && DB_S_COMMANDREEXECUTED!=hr) { goto END; } //Create an accessor if(!GetAccessorOnRowset(ON_ROWSET_ACCESSOR, DBACCESSOR_ROWDATA, DBPART_VALUE|DBPART_STATUS|DBPART_LENGTH, UPDATEABLE_COLS_BOUND)) goto END; if(!CHECK(InsertOneRow(g_ulNextRow, &HRow),S_OK)) goto END; //if can't see this insert then skip if (g_fRETURNPENDINGINSERTS&&g_fOWNINSERT&&g_fLITERALIDENITIY) { if(!(pData=(BYTE*)PROVIDER_ALLOC(m_cRowSize))) { goto END; } //get a data buffer with the inserted data if(!CHECK(FillInputBindings(m_pTable,DBACCESSOR_ROWDATA,m_cBinding,m_rgBinding, &pData,g_ulNextRow++,m_cRowsetCols,m_rgTableColOrds, PRIMARY),S_OK)) { goto END; } //Get a row handle, loop through the rowset looking for the row while (S_OK==(hr = m_pIRowset->GetNextRows(NULL,0,1,&cRows, &pHRow)) || hr == DB_S_ENDOFROWSET ) { if( cRows ==0) break; //Get the data for the ith row handle if(!CHECK(m_pIRowset->GetData(*pHRow,m_hAccessor,m_pData),S_OK)) { goto END; } //make sure GetData should be able to see the change if(CompareBuffer(m_pData,pData,m_cBinding,m_rgBinding,m_pIMalloc,TRUE,FALSE,COMPARE_ONLY)==TRUE) { fFound=TRUE; break; } if(!CHECK(m_pIRowset->ReleaseRows(1,pHRow,NULL,NULL,NULL),S_OK)) { goto END; } PROVIDER_FREE(pHRow); } //the inserted row has to be found if (!fFound) { goto END; } //IsSameRow should return DB_E_NEWLYINSERTED if DBPROP_STRONGIDENTITY //is VARIANT_FALSE only after the data has been transmitted to the back end //S_OK should be returned if(!CHECK(m_pIRowsetIdentity->IsSameRow(HRow, *pHRow),S_OK)) { goto END; } //binary comparision if(!CompareHandlesByLiteral(HRow, *pHRow,FALSE,TRUE)) { goto END; } //Undo the insertion if(!CHECK(UndoRows(1,&HRow),S_OK)) goto END; //IsSameRow should return DB_E_DELETEDROW, pending inserted rows undone are like //deleted rows if(!CHECK(m_pIRowsetIdentity->IsSameRow(HRow, *pHRow),DB_E_DELETEDROW)) { goto END; } //binary comparision if(!CompareHandlesByLiteral(HRow, *pHRow,FALSE,TRUE)) { goto END; } //Get Data should return DB_E_DELETEDROW if(CHECK(m_pIRowset->GetData(HRow,m_hAccessor,pData),DB_E_DELETEDROW)) { fTestPass=TRUE; } } else { fTestPass=TEST_SKIPPED; } END: if(HRow) CHECK(m_pIRowset->ReleaseRows(1,&HRow, NULL, NULL, NULL),S_OK); if(pHRow) CHECK(ReleaseRows(1, &pHRow, TRUE),S_OK); if(pData) PROVIDER_FREE(pData); ReleaseAccessorOnRowset(); if(fTestPass) return TEST_PASS; else return TEST_FAIL; } // }} // {{ TCW_TERMINATE_METHOD //-------------------------------------------------------------------- // @mfunc TestCase Termination Routine // // @rdesc TRUE or FALSE // BOOL Static_Cursor_Buffered::Terminate() { ReleaseRowsetAndAccessor(); // {{ TCW_TERM_BASECLASS_CHECK2 return(TCIRowsetIdentity::Terminate()); } // }} // }} // {{ TCW_TC_PROTOTYPE(Keyset_Query_Immediate) //*----------------------------------------------------------------------- //| Test Case: Keyset_Query_Immediate - Keyset_Query_Immediate //| Created: 05/28/96 //*----------------------------------------------------------------------- //-------------------------------------------------------------------- // @mfunc TestCase Initialization Routine // // @rdesc TRUE or FALSE // BOOL Keyset_Query_Immediate::Init() { DBPROPID rgGuid[7]; BOOL fCursorNotSupported = FALSE; DBPROPID rgGuidUnset[1]; ULONG cProp = 0; ULONG cPropUnset = 0; rgGuidUnset[0]=DBPROP_OTHERINSERT; cPropUnset=1; rgGuid[0]=DBPROP_IRowsetIdentity; rgGuid[1]=DBPROP_IRowsetChange; rgGuid[2]=DBPROP_OTHERUPDATEDELETE; rgGuid[3]=DBPROP_CANHOLDROWS; rgGuid[4]=DBPROP_CANSCROLLBACKWARDS; rgGuid[5]=DBPROP_IRowsetLocate; rgGuid[6]=KAGPROP_QUERYBASEDUPDATES; cProp=g_MSDASQL?7:6; if(!TCIRowsetIdentity::Init()) return FALSE; //check to see if the execute is going to fail if( !g_rgDBPrpt[IDX_ScrollBackwards].fSupported || !g_rgDBPrpt[IDX_CanHoldRows].fSupported || !g_rgDBPrpt[IDX_OtherUpdateDelete].fSupported ) { fCursorNotSupported = TRUE; odtLog << L"The Provider does not support a KEYSET Cursor.\n"; } //get a rowset with IRowsetIdentity, with keyset driven Cursor if(!GetRowsetAndAccessor(USE_OPENROWSET, cProp, rgGuid,cPropUnset,rgGuidUnset,NO_ACCESSOR)) { return TEST_SKIPPED; } if (!g_fTestValid) { return TRUE; } //has to be key cursor if(GetCursorType()==KEYSET_DRIVEN_CURSOR) { odtLog << L"This test will continue but a keyset cursor was not obtained.\n"; // return FALSE; } return TRUE; } // {{ TCW_VAR_PROTOTYPE(1) //*----------------------------------------------------------------------- // @mfunc Fetch one row. Move the cursor and fetch backwards to retrieve the same row handle. S_OK. // // @rdesc TEST_PASS or TEST_FAIL // int Keyset_Query_Immediate::Variation_1() { HROW rgHrow[2]; HROW *pHRow = rgHrow; DBCOUNTITEM cRows = 0; DBCOUNTITEM cRowCount = 0; BOOL fTestPass = FALSE; HRESULT hr; //if this test variation is not valid if (!g_fTestValid) { odtLog << L"The Provider does not support the properties that are necessary for this variation to execute.\n"; return TEST_SKIPPED; } //Restart the position to the begining of the rowset hr = m_pIRowset->RestartPosition(NULL); if (S_OK!=hr && DB_S_COMMANDREEXECUTED!=hr) { goto END; } //Get a row handle if(!CHECK(m_pIRowset->GetNextRows(NULL,8,1,&cRows, &pHRow),S_OK)) goto END; cRowCount++; //Get a row handle pHRow=&(rgHrow[1]); if(!CHECK(m_pIRowset->GetNextRows(NULL,-1,1,&cRows, &pHRow),S_OK)) goto END; cRowCount++; //IsSameRow should return S_OK if(!CHECK(m_pIRowsetIdentity->IsSameRow(rgHrow[0], rgHrow[1]),S_OK)) { goto END; } //binary comparision if(CompareHandlesByLiteral(rgHrow[0], rgHrow[1],FALSE,TRUE)) { fTestPass = TRUE; } END: CHECK(m_pIRowset->ReleaseRows(cRowCount, rgHrow, NULL, NULL, NULL),S_OK); if(fTestPass) return TEST_PASS; else return TEST_FAIL; } // }} // {{ TCW_VAR_PROTOTYPE(2) //*----------------------------------------------------------------------- // @mfunc Fetch hRowThis and change a non-key value. // Fetch the same row in hRowThat by IRowsetLocate::GetRowsByBookmark. S_OK. // // @rdesc TEST_PASS or TEST_FAIL // int Keyset_Query_Immediate::Variation_2() { DBORDINAL cColsNumber = 0; DBORDINAL *rgColsNumber = NULL; void *pData = NULL; HROW *pHRowThis = NULL; HROW *pHRowThat = NULL; DBCOUNTITEM cRows = 0; BOOL fTestPass = FALSE; HRESULT hr; //if this test variation is not valid if (!g_fTestValid) { odtLog << L"The Provider does not support the properties that are necessary for this variation to execute.\n"; return TEST_SKIPPED; } //If the provider is read only, skip the variation if(g_fReadOnlyProvider) return TEST_SKIPPED; //get non-key columns if(!GetNonKeyAndUpdatable(&cColsNumber, &rgColsNumber, m_pIMalloc)) goto END; //get an accessor if(!GetAccessorOnRowset(ON_ROWSET_ACCESSOR, DBACCESSOR_ROWDATA, DBPART_VALUE|DBPART_STATUS|DBPART_LENGTH, USE_COLS_TO_BIND_ARRAY, FORWARD, NO_COLS_BY_REF,DBTYPE_EMPTY, cColsNumber,rgColsNumber)) goto END; //Restart the position to the begining of the rowset hr = m_pIRowset->RestartPosition(NULL); if (S_OK!=hr && DB_S_COMMANDREEXECUTED!=hr) { goto END; } //get a row handle if(!CHECK(m_pIRowset->GetNextRows(NULL,5,1,&cRows,&pHRowThis),S_OK)) goto END; //change it if(!CHECK(ChangeOneRow(*pHRowThis, g_ulNextRow++, &pData),S_OK)) goto END; //Restart the position to the begining of the rowset hr = m_pIRowset->RestartPosition(NULL); if (S_OK!=hr && DB_S_COMMANDREEXECUTED!=hr) { goto END; } //get the row handle again if(!CHECK(m_pIRowset->GetNextRows(NULL,5,1,&cRows,&pHRowThat),S_OK)) goto END; //IsSameRow should return S_OK if(!CHECK(m_pIRowsetIdentity->IsSameRow(*pHRowThis, *pHRowThat),S_OK)) { goto END; } //binary comparision if(!CompareHandlesByLiteral(*pHRowThis, *pHRowThat,FALSE,TRUE)) { goto END; } //GetData on pHRowThat should return the updated data if(COMPARE(CheckExpectedData(*pHRowThat, pData, TRUE),TRUE)) fTestPass=TRUE; END: if(pData) ReleaseInputBindingsMemory(m_cBinding, m_rgBinding,(BYTE *)pData,TRUE); if(rgColsNumber) PROVIDER_FREE(rgColsNumber); if(pHRowThis) CHECK(ReleaseRows(1,&pHRowThis,TRUE),S_OK); if(pHRowThat) CHECK(ReleaseRows(1,&pHRowThat,TRUE),S_OK); ReleaseAccessorOnRowset(); if(fTestPass) return TEST_PASS; else return TEST_FAIL; } // {{ TCW_VAR_PROTOTYPE(3) //*----------------------------------------------------------------------- // @mfunc Hard deleted a row handle. Fetch the same row again forwards. // // @rdesc TEST_PASS or TEST_FAIL // int Keyset_Query_Immediate::Variation_3() { HROW *pHRow = NULL; HROW *pHRowSecond = NULL; DBCOUNTITEM cRows = 0; BOOL fTestPass = FALSE; DBROWSTATUS *pDBRowStatus = NULL; BOOL fPending = TRUE; HRESULT hr; //Restart the position to the begining of the rowset hr = m_pIRowset->RestartPosition(NULL); if (S_OK!=hr && DB_S_COMMANDREEXECUTED!=hr) { goto END; } //get a row handle if(!CHECK(m_pIRowset->GetNextRows(NULL,0,1,&cRows,&pHRow),S_OK)) goto END; //hard delete the row if(!CHECK(DeleteRows(1,pHRow),S_OK)) goto END; //get the same row again if(!CHECK(m_pIRowset->GetNextRows(NULL,-1,1,&cRows,&pHRowSecond),S_OK)) goto END; //IsSameRow should return DB_E_DELETEDROW because pHRow is being compared if(!CHECK(m_pIRowsetIdentity->IsSameRow(*pHRow, *pHRowSecond),DB_E_DELETEDROW)) { goto END; } //if test can see it own deletes these should compare if (g_fOWNUPDATEDELETE) { //binary comparision if(!CompareHandlesByLiteral(*pHRow, *pHRowSecond,FALSE,TRUE)) { goto END; } } else { //binary comparision if(CompareHandlesByLiteral(*pHRow, *pHRowSecond,FALSE,TRUE)) { goto END; } } if (g_fREMOVEDELETED) { //IsSameRow should return S_OK - REMOVEDELETED is TRUE if(!CHECK(m_pIRowsetIdentity->IsSameRow(*pHRowSecond, *pHRowSecond),S_OK)) { goto END; } //binary comparision if(!CompareHandlesByLiteral(*pHRowSecond, *pHRowSecond,FALSE,TRUE)) { goto END; } } else { //if test can see it own deletes if (g_fOWNUPDATEDELETE) { //IsSameRow should return DB_E_DELETEDROW REMOVEDELETED is FALSE if(!CHECK(m_pIRowsetIdentity->IsSameRow(*pHRowSecond, *pHRowSecond),DB_E_DELETEDROW)) { goto END; } //binary comparision - because a handle to a deleted row should compare with itself if(!CompareHandlesByLiteral(*pHRowSecond, *pHRowSecond,FALSE,TRUE)) { goto END; } } else { //IsSameRow should return DB_E_DELETEDROW REMOVEDELETED is FALSE //but so is g_fOWNUPDATEDELETE so deltes are not seen if(!CHECK(m_pIRowsetIdentity->IsSameRow(*pHRowSecond, *pHRowSecond),S_OK)) { goto END; } //binary comparision if(!CompareHandlesByLiteral(*pHRowSecond, *pHRowSecond,FALSE,TRUE)) { goto END; } } } fTestPass=TRUE; END: //undo the deletions if(pHRow) { CHECK(ReleaseRows(1, &pHRow,TRUE),S_OK); } if(pHRowSecond) CHECK(ReleaseRows(1, &pHRowSecond,TRUE),S_OK); if(pDBRowStatus) PROVIDER_FREE(pDBRowStatus); if(fTestPass) return TEST_PASS; else return TEST_FAIL; } // }} // {{ TCW_VAR_PROTOTYPE(4) //*----------------------------------------------------------------------- // @mfunc Hard deleted a row handle. Fetch the same row again backwards. // // @rdesc TEST_PASS or TEST_FAIL // int Keyset_Query_Immediate::Variation_4() { HROW *pHRow = NULL; HROW *pHRowSecond = NULL; DBCOUNTITEM cRows = 0; BOOL fTestPass = FALSE; DBROWSTATUS *pDBRowStatus = NULL; BOOL fPending = TRUE; HRESULT hr; //Restart the position to the begining of the rowset hr = m_pIRowset->RestartPosition(NULL); if (S_OK!=hr && DB_S_COMMANDREEXECUTED!=hr) { goto END; } //get a row handle if(!CHECK(m_pIRowset->GetNextRows(NULL,1,1,&cRows,&pHRow),S_OK)) goto END; //hard delete the row if(!CHECK(DeleteRows(1,pHRow),S_OK)) goto END; //get the same row again if(!CHECK(m_pIRowset->GetNextRows(NULL,0,-1,&cRows,&pHRowSecond),S_OK)) goto END; //IsSameRow should return DB_E_DELETEDROW because pHRow is being compared if(!CHECK(m_pIRowsetIdentity->IsSameRow(*pHRow, *pHRowSecond),DB_E_DELETEDROW)) { goto END; } //if test can see it own deletes these should compare if (g_fOWNUPDATEDELETE) { //binary comparision if(!CompareHandlesByLiteral(*pHRow, *pHRowSecond,FALSE,TRUE)) { goto END; } } else { //binary comparision if(CompareHandlesByLiteral(*pHRow, *pHRowSecond,FALSE,TRUE)) { goto END; } } if (g_fREMOVEDELETED) { //IsSameRow should return S_OK - REMOVEDELETED is TRUE if(!CHECK(m_pIRowsetIdentity->IsSameRow(*pHRowSecond, *pHRowSecond),S_OK)) { goto END; } //binary comparision if(!CompareHandlesByLiteral(*pHRowSecond, *pHRowSecond,FALSE,TRUE)) { goto END; } } else { //if test can see it own deletes if (g_fOWNUPDATEDELETE) { //IsSameRow should return DB_E_DELETEDROW REMOVEDELETED is FALSE if(!CHECK(m_pIRowsetIdentity->IsSameRow(*pHRowSecond, *pHRowSecond),DB_E_DELETEDROW)) { goto END; } //binary comparision - because a handle to a deleted row should compare with itself if(!CompareHandlesByLiteral(*pHRowSecond, *pHRowSecond,FALSE,TRUE)) { goto END; } } else { //IsSameRow should return DB_E_DELETEDROW REMOVEDELETED is FALSE //but so is g_fOWNUPDATEDELETE so deltes are not seen if(!CHECK(m_pIRowsetIdentity->IsSameRow(*pHRowSecond, *pHRowSecond),S_OK)) { goto END; } //binary comparision if(!CompareHandlesByLiteral(*pHRowSecond, *pHRowSecond,FALSE,TRUE)) { goto END; } } } fTestPass=TRUE; END: //undo the deletions if(pHRow) { CHECK(ReleaseRows(1, &pHRow,TRUE),S_OK); } if(pHRowSecond) CHECK(ReleaseRows(1, &pHRowSecond,TRUE),S_OK); if(pDBRowStatus) PROVIDER_FREE(pDBRowStatus); if(fTestPass) return TEST_PASS; else return TEST_FAIL; } // }} // {{ TCW_VAR_PROTOTYPE(5) //*----------------------------------------------------------------------- // @mfunc Hard deleted the last row handle. Fetch the same row again backwards. // // @rdesc TEST_PASS or TEST_FAIL // int Keyset_Query_Immediate::Variation_5() { HROW rgHRow[50]; HROW *pHRow = NULL; HROW *pHRowSecond = NULL; DBCOUNTITEM cRows = 0; BOOL fTestPass = FALSE; DBROWSTATUS *pDBRowStatus = NULL; BOOL fPending = TRUE; HRESULT hr; DWORD count = 0; DWORD i = 0; //Restart the position to the begining of the rowset hr = m_pIRowset->RestartPosition(NULL); if (S_OK!=hr && DB_S_COMMANDREEXECUTED!=hr) { goto END; } //Get the row handle at the end of the rowset by looping through the rowset till ENDOFROWSET pHRow=&rgHRow[count]; while (S_OK==(hr = m_pIRowset->GetNextRows(NULL,0,1,&cRows, &pHRow)) || DB_S_ENDOFROWSET==hr) { if (DB_S_ENDOFROWSET==hr) { if( cRows ==0) { break; } else { goto END; } } pHRow=&rgHRow[++count]; } //release and free all but the last pHRow=&rgHRow[0]; CHECK(ReleaseRows((count-1), &pHRow,FALSE),S_OK); //set the pointer to the last row handle pHRow=&rgHRow[count-1]; //hard delete the row if(!CHECK(DeleteRows(1,pHRow),S_OK)) goto END; //get the same row again if(!CHECK(m_pIRowset->GetNextRows(NULL,0,-1,&cRows,&pHRowSecond),S_OK)) { goto END; } //IsSameRow should return DB_E_DELETEDROW because pHRow is being compared if(!CHECK(m_pIRowsetIdentity->IsSameRow(*pHRow, *pHRowSecond),DB_E_DELETEDROW)) { goto END; } //if test can see it own deletes these should compare if (g_fOWNUPDATEDELETE) { //binary comparision if(!CompareHandlesByLiteral(*pHRow, *pHRowSecond,FALSE,TRUE)) { goto END; } } else { //binary comparision if(CompareHandlesByLiteral(*pHRow, *pHRowSecond,FALSE,TRUE)) { goto END; } } if (g_fREMOVEDELETED) { //IsSameRow should return S_OK - REMOVEDELETED is TRUE if(!CHECK(m_pIRowsetIdentity->IsSameRow(*pHRowSecond, *pHRowSecond),S_OK)) { goto END; } //binary comparision if(!CompareHandlesByLiteral(*pHRowSecond, *pHRowSecond,FALSE,TRUE)) { goto END; } } else { //if test can see it own deletes if (g_fOWNUPDATEDELETE) { //IsSameRow should return DB_E_DELETEDROW REMOVEDELETED is FALSE if(!CHECK(m_pIRowsetIdentity->IsSameRow(*pHRowSecond, *pHRowSecond),DB_E_DELETEDROW)) { goto END; } //binary comparision - because a handle to a deleted row should compare with itself if(!CompareHandlesByLiteral(*pHRowSecond, *pHRowSecond,FALSE,TRUE)) { goto END; } } else { //IsSameRow should return DB_E_DELETEDROW REMOVEDELETED is FALSE //but so is g_fOWNUPDATEDELETE so deltes are not seen if(!CHECK(m_pIRowsetIdentity->IsSameRow(*pHRowSecond, *pHRowSecond),S_OK)) { goto END; } //binary comparision if(!CompareHandlesByLiteral(*pHRowSecond, *pHRowSecond,FALSE,TRUE)) { goto END; } } } fTestPass=TRUE; END: //undo the deletions if(pHRow) { CHECK(ReleaseRows(1, &pHRow,FALSE),S_OK); } if(pHRowSecond) CHECK(ReleaseRows(1, &pHRowSecond,TRUE),S_OK); if(pDBRowStatus) PROVIDER_FREE(pDBRowStatus); if(fTestPass) return TEST_PASS; else return TEST_FAIL; } // }} // {{ TCW_VAR_PROTOTYPE(6) //*----------------------------------------------------------------------- // @mfunc Hard deleted the last row handle. Fetch the same row again forwards. // // @rdesc TEST_PASS or TEST_FAIL // int Keyset_Query_Immediate::Variation_6() { HROW *pHRow = NULL; HROW *pHRowSecond = NULL; DBCOUNTITEM cRows = 0; BOOL fTestPass = FALSE; DBROWSTATUS *pDBRowStatus = NULL; BOOL fPending = TRUE; HRESULT hr; DWORD count = 0; HROW rgHRow[50]; //Restart the position to the begining of the rowset hr = m_pIRowset->RestartPosition(NULL); if (S_OK!=hr && DB_S_COMMANDREEXECUTED!=hr) { goto END; } //Get the row handle at the end of the rowset by looping through the rowset till ENDOFROWSET pHRow=&rgHRow[count]; while (S_OK==(hr = m_pIRowset->GetNextRows(NULL,0,1,&cRows, &pHRow)) || DB_S_ENDOFROWSET==hr) { if (DB_S_ENDOFROWSET==hr) { if( cRows ==0) { break; } else { goto END; } } pHRow=&rgHRow[++count]; } //release all but the last pHRow=&rgHRow[0]; CHECK(ReleaseRows((count-1), &pHRow,FALSE),S_OK); //set the pointer to the last row handle pHRow=&rgHRow[count-1]; //hard delete the row, it may be gone from variation 5 (if so ok it just needs //to be deleted hr=DeleteRows(1,pHRow); if (hr != S_OK && hr!= DB_E_ERRORSOCCURRED) { goto END; } //get the same row again if(!CHECK(m_pIRowset->GetNextRows(NULL,-1,1,&cRows,&pHRowSecond),S_OK)) goto END; //IsSameRow should return DB_E_DELETEDROW because pHRow is being compared if(!CHECK(m_pIRowsetIdentity->IsSameRow(*pHRow, *pHRowSecond),DB_E_DELETEDROW)) { goto END; } //if test can see it own deletes these should compare if (g_fOWNUPDATEDELETE) { //binary comparision if(!CompareHandlesByLiteral(*pHRow, *pHRowSecond,FALSE,TRUE)) { goto END; } } else { //binary comparision if(CompareHandlesByLiteral(*pHRow, *pHRowSecond,FALSE,TRUE)) { goto END; } } if (g_fREMOVEDELETED) { //IsSameRow should return S_OK - REMOVEDELETED is TRUE if(!CHECK(m_pIRowsetIdentity->IsSameRow(*pHRowSecond, *pHRowSecond),S_OK)) { goto END; } //binary comparision if(!CompareHandlesByLiteral(*pHRowSecond, *pHRowSecond,FALSE,TRUE)) { goto END; } } else { //if test can see it own deletes if (g_fOWNUPDATEDELETE) { //IsSameRow should return DB_E_DELETEDROW REMOVEDELETED is FALSE if(!CHECK(m_pIRowsetIdentity->IsSameRow(*pHRowSecond, *pHRowSecond),DB_E_DELETEDROW)) { goto END; } //binary comparision - because a handle to a deleted row should compare with itself if(!CompareHandlesByLiteral(*pHRowSecond, *pHRowSecond,FALSE,TRUE)) { goto END; } } else { //IsSameRow should return DB_E_DELETEDROW REMOVEDELETED is FALSE //but so is g_fOWNUPDATEDELETE so deltes are not seen if(!CHECK(m_pIRowsetIdentity->IsSameRow(*pHRowSecond, *pHRowSecond),S_OK)) { goto END; } //binary comparision if(!CompareHandlesByLiteral(*pHRowSecond, *pHRowSecond,FALSE,TRUE)) { goto END; } } } fTestPass=TRUE; END: //undo the deletions if(pHRow) { CHECK(ReleaseRows(1, &pHRow,FALSE),S_OK); } if(pHRowSecond) CHECK(ReleaseRows(1, &pHRowSecond,TRUE),S_OK); if(pDBRowStatus) PROVIDER_FREE(pDBRowStatus); if(fTestPass) return TEST_PASS; else return TEST_FAIL; } // }} // }} // {{ TCW_TERMINATE_METHOD //-------------------------------------------------------------------- // @mfunc TestCase Termination Routine // // @rdesc TRUE or FALSE // BOOL Keyset_Query_Immediate::Terminate() { ReleaseRowsetAndAccessor(); // {{ TCW_TERM_BASECLASS_CHECK2 return(TCIRowsetIdentity::Terminate()); } // }} // }} // {{ TCW_TC_PROTOTYPE(Keyset_Cursor_Buffered) //*----------------------------------------------------------------------- //| Test Case: Keyset_Cursor_Buffered - Keyset_Cursor_Buffered //| Created: 05/28/96 //*----------------------------------------------------------------------- //-------------------------------------------------------------------- // @mfunc TestCase Initialization Routine // // @rdesc TRUE or FALSE // BOOL Keyset_Cursor_Buffered::Init() { DBPROPID rgGuid[9]; BOOL fCursorNotSupported = FALSE; DBPROPID rgGuidUnset[2]; ULONG cProp = 0; ULONG cPropUnset = 0; rgGuidUnset[0]=DBPROP_OTHERINSERT; rgGuidUnset[1]=DBPROP_REMOVEDELETED; cPropUnset=1; rgGuid[0]=DBPROP_IRowsetIdentity; rgGuid[1]=DBPROP_IRowsetChange; rgGuid[2]=DBPROP_IRowsetLocate; rgGuid[3]=DBPROP_CANHOLDROWS; rgGuid[4]=DBPROP_CANSCROLLBACKWARDS; rgGuid[5]=DBPROP_OTHERUPDATEDELETE; rgGuid[6]=DBPROP_IRowsetUpdate; rgGuid[7]=DBPROP_OWNINSERT; rgGuid[8]=DBPROP_OWNUPDATEDELETE; cProp=9; if(!TCIRowsetIdentity::Init()) return FALSE; //check to see if the execute is going to fail if( !g_rgDBPrpt[IDX_ScrollBackwards].fSupported || !g_rgDBPrpt[IDX_CanHoldRows].fSupported || !g_rgDBPrpt[IDX_OtherUpdateDelete].fSupported ) { fCursorNotSupported = TRUE; odtLog << L"The Provider does not support a KEYSET Cursor.\n"; } //get a rowset with IRowsetIdentity, with keyset driven Cursor if(!GetRowsetAndAccessor(USE_OPENROWSET, cProp, rgGuid,cPropUnset,rgGuidUnset,ON_ROWSET_ACCESSOR)) { return TEST_SKIPPED; } if (!g_fTestValid) { return TRUE; } //has to be keyset cursor if(GetCursorType()==KEYSET_DRIVEN_CURSOR) { odtLog << L"This test will continue but a keyset cursor was not obtained.\n"; // return FALSE; } return TRUE; } // {{ TCW_VAR_PROTOTYPE(1) //*----------------------------------------------------------------------- // @mfunc Fetch one row. Move the cursor and fetch backwards to retrieve the same row handle by // IRowsetLocate::GetRowsByBookmark. S_OK. // // @rdesc TEST_PASS or TEST_FAIL // int Keyset_Cursor_Buffered::Variation_1() { HROW *pHRow =NULL; HROW *pHRowSecond =NULL; DBCOUNTITEM cRows =0; DBBOOKMARK DBBookmark =DBBMK_FIRST; BYTE *pBookmark =(BYTE *)&DBBookmark; BOOL fTestPass =FALSE; //if this test variation is not valid if (!g_fTestValid) { odtLog << L"The Provider does not support the properties that are necessary for this variation to execute.\n"; return TEST_PASS; } //get the 4th row handle if(!CHECK(m_pIRowset->GetNextRows(NULL,3,1,&cRows,&pHRow),S_OK)) goto END; //get the same row again by IRowsetLocate::GetRowsAt if(!CHECK(m_pIRowsetLocate->GetRowsAt(NULL,NULL,1,pBookmark,3,-1, &cRows,&pHRowSecond),S_OK)) goto END; //IsSameRow should return S_OK if(!CHECK(m_pIRowsetIdentity->IsSameRow(*pHRow, *pHRowSecond),S_OK)) { goto END; } //binary comparision if(CompareHandlesByLiteral(*pHRow, *pHRowSecond,FALSE,TRUE)) { fTestPass = TRUE; } END: //release the row if(pHRow) CHECK(ReleaseRows(1, &pHRow,TRUE),S_OK); if(pHRowSecond) CHECK(ReleaseRows(1, &pHRowSecond,TRUE),S_OK); if(fTestPass) return TEST_PASS; else return TEST_FAIL; } // }} // {{ TCW_VAR_PROTOTYPE(2) //*----------------------------------------------------------------------- // @mfunc Soft deleted the 1st row handle. Fetch the row handle again. S_OK. // // @rdesc TEST_PASS or TEST_FAIL // int Keyset_Cursor_Buffered::Variation_2() { HROW *pHRow = NULL; HROW HRowSecond = DB_NULL_HROW; DBCOUNTITEM cRows = 0; DBCOUNTITEM cbBookmark = 0; BYTE *pBookmark = NULL; BOOL fTestPass = FALSE; DBROWSTATUS DBRowStatus[1]; DBROWSTATUS *pDBRowStatus = NULL; HRESULT hr; //if this test variation is not valid if (!g_fTestValid) { odtLog << L"The Provider does not support the properties that are necessary for this variation to execute.\n"; return TEST_PASS; } //if IRowsetChange not available because conformance won't allow it //For read only provider or IRowsetChange not available, skip this variation if(g_fReadOnlyProvider || !(g_fROWSETUPDATABLE)) { odtLog << L"Can not get to IRowsetChange, can not insert a row.\n"; return TEST_PASS; } //If the provider is read only, skip the variation if(g_fReadOnlyProvider) { return TEST_PASS; } //Restart the position to the begining of the rowset hr = m_pIRowset->RestartPosition(NULL); if (S_OK!=hr && DB_S_COMMANDREEXECUTED!=hr) { goto END; } //get a row handle if(!CHECK(m_pIRowset->GetNextRows(NULL,0,1,&cRows,&pHRow),S_OK)) { goto END; } //get the bookmark for the row handle if(!GetBookmark(1, &cbBookmark, &pBookmark)) { goto END; } //soft delete the row if(!CHECK(DeleteRows(1,pHRow),S_OK)) { goto END; } //determine through props which row is fetched and check it //is the deleted row removed if (g_fOWNUPDATEDELETE&&g_fLITERALIDENITIY&&!g_fREMOVEDELETED) { //get the same row again by IRowsetLocate::GetRowsByBookmark if(!CHECK(m_pIRowsetLocate->GetRowsByBookmark(NULL,1,&cbBookmark, (const BYTE **)&pBookmark,&HRowSecond,&DBRowStatus[0]),DB_E_ERRORSOCCURRED)) { goto END; } COMPARE(DBRowStatus[0],DBROWSTATUS_E_INVALID); } else { //get the same row again by IRowsetLocate::GetRowsByBookmark if(!CHECK(m_pIRowsetLocate->GetRowsByBookmark(NULL,1,&cbBookmark, (const BYTE **)&pBookmark,&HRowSecond,&DBRowStatus[0]),S_OK)) { goto END; } COMPARE(DBRowStatus[0],DBROWSTATUS_S_OK); //is the deleted row present if (g_fOWNUPDATEDELETE) { //IsSameRow should return S_OK, should not see DB_E_DELTEDROW because //pending deleted row has not been transmitted to the back end as of yet if(!CHECK(m_pIRowsetIdentity->IsSameRow(*pHRow, HRowSecond),S_OK)) { goto END; } //binary comparision if(CompareHandlesByLiteral(*pHRow, HRowSecond,FALSE,TRUE)) { fTestPass = TRUE; } } else { //IsSameRow should return S_OK if(!CHECK(m_pIRowsetIdentity->IsSameRow(*pHRow, HRowSecond),S_OK)) { goto END; } //binary comparision if(CompareHandlesByLiteral(*pHRow, HRowSecond,FALSE,TRUE)) { fTestPass = TRUE; } } //Update the data, deletes are no longer pending if(!CHECK(UpdateRows(1,pHRow,&pDBRowStatus),S_OK)) { goto END; } //IsSameRow should return DB_E_DELETEDROW because pHRow1 points to a xmitted deleted //row if(!CHECK(m_pIRowsetIdentity->IsSameRow(*pHRow, HRowSecond),DB_E_DELETEDROW)) { goto END; } //binary comparision, these rows can't possibly compare literally if(!CompareHandlesByLiteral(*pHRow, HRowSecond,FALSE,FALSE)) { goto END; } if (g_fREMOVEDELETED) { //IsSameRow should return S_OK because the deleted row is removed if(!CHECK(m_pIRowsetIdentity->IsSameRow(HRowSecond, HRowSecond),S_OK)) { goto END; } //binary comparision, these rows can compare literally if(!CompareHandlesByLiteral(HRowSecond, HRowSecond,FALSE,TRUE)) { goto END; } } else { //IsSameRow should return DB_E_DELETEDROW the deleted row is not removed which is //pointed to by pHRow1AfterDel if(!CHECK(m_pIRowsetIdentity->IsSameRow(HRowSecond, HRowSecond),DB_E_DELETEDROW)) { goto END; } //binary comparision if(!CompareHandlesByLiteral(HRowSecond, HRowSecond,FALSE,FALSE)) { goto END; } } } fTestPass=TRUE; END: //undo the deletions if(pHRow) CHECK(UndoRows(1, pHRow),S_OK); if(pHRow) CHECK(ReleaseRows(1, &pHRow,TRUE),S_OK); if(HRowSecond!=DB_NULL_HROW) CHECK(m_pIRowset->ReleaseRows(1, &HRowSecond, NULL, NULL, NULL),S_OK); //release the bookmark if(pBookmark) PROVIDER_FREE(pBookmark); if(pDBRowStatus) PROVIDER_FREE(pDBRowStatus); if(fTestPass) return TEST_PASS; else return TEST_FAIL; } // }} // {{ TCW_VAR_PROTOTYPE(3) //*----------------------------------------------------------------------- // @mfunc Fetch hRowThis and change a non-key value. Fetch the same row in hRowThat. // IsSameRow should return S_OK. // // @rdesc TEST_PASS or TEST_FAIL // int Keyset_Cursor_Buffered::Variation_3() { void *pData1 = NULL; void *pData2 = NULL; HROW *pHRowThis = NULL; HROW *pHRowThat = NULL; DBCOUNTITEM cRows = 0; BOOL fTestPass = FALSE; HRESULT hr; //get an accessor if(!GetAccessorOnRowset(ON_ROWSET_ACCESSOR, DBACCESSOR_ROWDATA, DBPART_VALUE|DBPART_STATUS|DBPART_LENGTH, UPDATEABLE_COLS_BOUND)) goto END; //Restart the position to the begining of the rowset hr = m_pIRowset->RestartPosition(NULL); if (S_OK!=hr && DB_S_COMMANDREEXECUTED!=hr) { goto END; } //get a row handle if(!CHECK(m_pIRowset->GetNextRows(NULL,9,1,&cRows,&pHRowThis),S_OK)) goto END; //get the data for the row if(!CHECK(m_pIRowset->GetData(*pHRowThis, m_hAccessor, m_pData),S_OK)) goto END; //change it if(!CHECK(ChangeOneRow(*pHRowThis, g_ulNextRow++, &pData1),S_OK)) goto END; //get the row handle again if(!CHECK(m_pIRowset->GetNextRows(NULL,-1,1,&cRows,&pHRowThat),S_OK)) goto END; //IsSameRow should return S_OK if(!CHECK(m_pIRowsetIdentity->IsSameRow(*pHRowThis, *pHRowThat),S_OK)) { goto END; } //binary comparision if(!CompareHandlesByLiteral(*pHRowThis, *pHRowThat,FALSE,TRUE)) { goto END; } //will this rowset see its pending changes if (g_fLITERALIDENITIY&&g_fOWNUPDATEDELETE) { //GetData on pHRowThat, should return the updated data buffer if(!COMPARE(CheckExpectedData(*pHRowThat, pData1, TRUE),TRUE)) goto END; } else { //GetData on pHRowThat, should return the first data because //LI is false (pending changes are not seen) //the old buffer should be here if(!COMPARE(CheckExpectedData(*pHRowThat, m_pData, TRUE),TRUE)) goto END; } //change data by pHRowThat if(!CHECK(ChangeOneRow(*pHRowThat, g_ulNextRow++, &pData2),S_OK)) goto END; //this rowset will see its pending change only if DBPROP_LITERALIDENTITY is TRUE AND OWNUPDEL is TRUE //if LI is FALSE pending changes are not seen if (g_fLITERALIDENITIY&&g_fOWNUPDATEDELETE) { if(!COMPARE(CheckExpectedData(*pHRowThis, pData2, TRUE),TRUE)) goto END; } else { if(!COMPARE(CheckExpectedData(*pHRowThis, pData1, TRUE),TRUE)) goto END; } //Undo hRowThat //same rules apply for Undo as for visibility of pending changes //if LI is TRUE test just undid all changes //eles it just undid changes on hRowThat if(!CHECK(UndoRows(1,pHRowThat),S_OK)) goto END; //this rowset will see its pending change only if DBPROP_LITERALIDENTITY is TRUE AND OWNUPDEL is TRUE //if LI is FALSE pending changes are not seen if (g_fLITERALIDENITIY&&g_fOWNUPDATEDELETE) { //GetData on pHRowThis should return its first change if(!COMPARE(CheckExpectedData(*pHRowThis, m_pData, TRUE),TRUE)) goto END; } else { //GetData on pHRowThis should return its first change if(!COMPARE(CheckExpectedData(*pHRowThis, pData1, TRUE),TRUE)) goto END; } //release the one row handle(this) if(pHRowThis) CHECK(ReleaseRows(1,&pHRowThis,TRUE),S_OK); //get the row handle again. if(!CHECK(m_pIRowset->GetNextRows(NULL,-1,1,&cRows,&pHRowThis),S_OK)) goto END; //IsSameRow should return S_OK (the row will always be the row, just the data might be chaged) if(!CHECK(m_pIRowsetIdentity->IsSameRow(*pHRowThis, *pHRowThat),S_OK)) { goto END; } //binary comparision if(!CompareHandlesByLiteral(*pHRowThis, *pHRowThat,FALSE,TRUE)) { goto END; } //this rowset will see its pending change only if DBPROP_LITERALIDENTITY is TRUE AND OWNUPDEL is TRUE //if LI is FALSE pending changes are not seen if (g_fLITERALIDENITIY&&g_fOWNUPDATEDELETE) { //GetData on pHRowThat should return row after undo if(!COMPARE(CheckExpectedData(*pHRowThat, m_pData, TRUE),TRUE)) goto END; } else { //GetData on pHRowThat should return the row's first change if(!COMPARE(CheckExpectedData(*pHRowThat, pData2, TRUE),TRUE)) goto END; } fTestPass=TRUE; END: if(m_pData) ReleaseInputBindingsMemory(m_cBinding, m_rgBinding,(BYTE *)m_pData,FALSE); if(pData1) ReleaseInputBindingsMemory(m_cBinding, m_rgBinding,(BYTE *)pData1,FALSE); if(pData2) ReleaseInputBindingsMemory(m_cBinding, m_rgBinding,(BYTE *)pData2,TRUE); if(pHRowThis) CHECK(ReleaseRows(1,&pHRowThis,TRUE),S_OK); if(pHRowThat) CHECK(ReleaseRows(1,&pHRowThat,TRUE),S_OK); if(fTestPass) return TEST_PASS; else return TEST_FAIL; } // }} // {{ TCW_VAR_PROTOTYPE(4) //*----------------------------------------------------------------------- // @mfunc Insert a new row into the rowset. Undo // // @rdesc TEST_PASS or TEST_FAIL // int Keyset_Cursor_Buffered::Variation_4() { HROW HRow = NULL; HROW *pHRow = NULL; DBCOUNTITEM cRows = 0; BYTE *pData = NULL; BOOL fTestPass = FALSE; HRESULT hr; BOOL fFound = FALSE; //Restart the position to the begining of the rowset hr = m_pIRowset->RestartPosition(NULL); if (S_OK!=hr && DB_S_COMMANDREEXECUTED!=hr) { goto END; } //Create an accessor if(!GetAccessorOnRowset(ON_ROWSET_ACCESSOR, DBACCESSOR_ROWDATA, DBPART_VALUE|DBPART_STATUS|DBPART_LENGTH, UPDATEABLE_COLS_BOUND)) goto END; if(!CHECK(InsertOneRow(g_ulNextRow, &HRow),S_OK)) goto END; //if can't see this insert then skip if (g_fRETURNPENDINGINSERTS&&g_fOWNINSERT&&g_fLITERALIDENITIY) { if(!(pData=(BYTE*)PROVIDER_ALLOC(m_cRowSize))) goto END; //get a data buffer with the inserted data if(!CHECK(FillInputBindings(m_pTable,DBACCESSOR_ROWDATA,m_cBinding,m_rgBinding, &pData,g_ulNextRow++,m_cRowsetCols,m_rgTableColOrds, PRIMARY),S_OK)) { goto END; } //Get a row handle while (S_OK==(hr = m_pIRowset->GetNextRows(NULL,0,1,&cRows, &pHRow)) || hr == DB_S_ENDOFROWSET ) { if( cRows ==0) break; //Get the data for the ith row handle if(!CHECK(m_pIRowset->GetData(*pHRow,m_hAccessor,m_pData),S_OK)) { goto END; } //make sure GetData should be able to see the change if(CompareBuffer(m_pData,pData,m_cBinding,m_rgBinding,m_pIMalloc,TRUE,FALSE,COMPARE_ONLY)==TRUE) { fFound=TRUE; break; } if(!CHECK(m_pIRowset->ReleaseRows(1,pHRow,NULL,NULL,NULL),S_OK)) { goto END; } PROVIDER_FREE(pHRow); } //the inserted row has to be found if (!fFound) { goto END; } //IsSameRow should return DB_E_NEWLYINSERTED if DBPROP_STRONGIDENTITY //is VARIANT_FALSE only after the data has been transmitted to the back end //S_OK should be returned if(!CHECK(m_pIRowsetIdentity->IsSameRow(HRow, *pHRow),S_OK)) { goto END; } //binary comparision if(!CompareHandlesByLiteral(HRow, *pHRow,FALSE,TRUE)) { goto END; } //Undo the insertion if(!CHECK(UndoRows(1,&HRow),S_OK)) goto END; //IsSameRow should return DB_E_DELETEDROW, pending inserted rows undone are like //deleted rows if(!CHECK(m_pIRowsetIdentity->IsSameRow(HRow, *pHRow),DB_E_DELETEDROW)) { goto END; } //binary comparision if(!CompareHandlesByLiteral(HRow, *pHRow,FALSE,TRUE)) { goto END; } //Get Data should return DB_E_DELETEDROW if(CHECK(m_pIRowset->GetData(HRow,m_hAccessor,pData),DB_E_DELETEDROW)) { fTestPass=TRUE; } } else { fTestPass=TEST_SKIPPED; } END: if(HRow) CHECK(m_pIRowset->ReleaseRows(1,&HRow, NULL, NULL, NULL),S_OK); if(pHRow) CHECK(ReleaseRows(1, &pHRow, TRUE),S_OK); if(pData) PROVIDER_FREE(pData); if(fTestPass) return TEST_PASS; else return TEST_FAIL; } // }} // {{ TCW_VAR_PROTOTYPE(5) //*----------------------------------------------------------------------- // @mfunc Fetch hRowThis and soft change the key of the row. // The row should be deleted and a new row is appended at the end of rowset. // // @rdesc TEST_PASS or TEST_FAIL // int Keyset_Cursor_Buffered::Variation_5() { HROW *pHRowLast1 = NULL; HROW *pHRowLast2 = NULL; HROW *pHRow1 = NULL; HROW *pHRow2 = NULL; HROW *pHRow3 = NULL; HROW *pHRowNext = NULL; DBCOUNTITEM cRows = 0; void *pData2 = NULL; HRESULT hr; DBBOOKMARK DBBkmrkLST = DBBMK_LAST; BYTE *pBkmrkLST = (BYTE *)&DBBkmrkLST; DBBOOKMARK DBBkmrkFRST = DBBMK_FIRST; BYTE *pBkmrkFRST = (BYTE *)&DBBkmrkFRST; BOOL fTestPass = FALSE; BOOL fNewRow = FALSE; ULONG cColsNumber = 0; ULONG cColsCount = 0; //if this test variation is not valid if (!g_fTestValid) { odtLog << L"The Provider does not support the properties that are necessary for this variation to execute.\n"; return TEST_PASS; } //Get the row handle at the end of the rowset if(!CHECK(m_pIRowsetLocate->GetRowsAt(NULL,NULL,1,pBkmrkLST,0,1,&cRows, &pHRowLast1),S_OK)) { goto END; } //If the provider is read only, skip the variation if(g_fReadOnlyProvider) return TEST_PASS; //Restart the position to the begining of the rowset hr = m_pIRowset->RestartPosition(NULL); if (S_OK!=hr && DB_S_COMMANDREEXECUTED!=hr) { goto END; } //Create an accessor if(!GetAccessorOnRowset(ON_ROWSET_ACCESSOR, DBACCESSOR_ROWDATA, DBPART_VALUE|DBPART_STATUS|DBPART_LENGTH, UPDATEABLE_COLS_BOUND)) goto END; //get a row handle if(!CHECK(m_pIRowset->GetNextRows(NULL,1,1,&cRows,&pHRow1),S_OK)) { goto END; } //Restart the position to the begining of the rowset hr = m_pIRowset->RestartPosition(NULL); if (S_OK!=hr && DB_S_COMMANDREEXECUTED!=hr) { goto END; } //get the 2nd row handle again if(!CHECK(m_pIRowset->GetNextRows(NULL,1,1,&cRows,&pHRow2),S_OK)) { goto END; } //get a third row handle if(!CHECK(m_pIRowset->GetNextRows(NULL,0,1,&cRows,&pHRowNext),S_OK)) { goto END; } //these should be the same rows if(!CHECK(m_pIRowsetIdentity->IsSameRow(*pHRow2, *pHRow1),S_OK)) { goto END; } //binary comparision if(!CompareHandlesByLiteral(*pHRow2, *pHRow1,FALSE,TRUE)) { goto END; } //change the row through the 2nd row handle if(!CHECK(ChangeOneRow(*pHRow2,g_ulNextRow++),S_OK)) { goto END; } //Update the change, xmit it to the back end if(!CHECK(UpdateRows(1,pHRow2),S_OK)) { goto END; } //these should still be the same rows if(!CHECK(m_pIRowsetIdentity->IsSameRow(*pHRow2, *pHRow1),S_OK)) { goto END; } //binary comparision if(!CompareHandlesByLiteral(*pHRow2, *pHRow1,FALSE,TRUE)) { goto END; } //Restart the position to the begining of the rowset hr = m_pIRowset->RestartPosition(NULL); if (S_OK!=hr && DB_S_COMMANDREEXECUTED!=hr) { goto END; } //Get the row handle at the end of the rowset if(!CHECK(m_pIRowsetLocate->GetRowsAt(NULL,NULL,1,pBkmrkLST,0,1,&cRows, &pHRowLast2),S_OK)) { goto END; } //if the row at the end of the rowset is not the previous row at the end of the rowset //and newly inserted rows are visibile then //the new row (pHRow2) is inserted at the end hr=m_pIRowsetIdentity->IsSameRow(*pHRowLast1, *pHRowLast2); if(hr!=S_OK&&g_fOWNINSERT) { //IsSameRow *MIGHT* return DB_E_NEWLYINSERTED if DBPROP_STRONGIDENTITY is VARIANT_FALSE. //DBPROP_STRONGIDENTITY FALSE means newly inserted row can not be seen if(g_rgDBPrpt[IDX_StrongIdentity].fDefault==VARIANT_FALSE) { m_hr=m_pIRowsetIdentity->IsSameRow(*pHRow2, *pHRowLast2); if ( m_hr!=ResultFromScode(S_FALSE) && m_hr!=ResultFromScode(DB_E_NEWLYINSERTED) ) { goto END; } } //can compare newly inserted rows else { m_hr=m_pIRowsetIdentity->IsSameRow(*pHRow2, *pHRowLast2); //new row should not match deleted row if (m_hr!=ResultFromScode(S_FALSE)) { goto END; } } fNewRow=TRUE; //this also means the old row should have been deleted, Update was called so //see if GetData on the old row handle gets the data or returns DB_E_DELETEDROW. //S_OK is possible here. even though the test did not delete the row (the provider might have) //so pHRow2 becomes invalid and provider behavior in this case is undefined, //short of a GPF that is. if(!(pData2=PROVIDER_ALLOC(m_cRowSize))) { goto END; } m_hr=m_pIRowset->GetData(*pHRow2, m_hAccessor, pData2); if (DB_E_DELETEDROW != m_hr && S_OK != m_hr) { goto END; } } else//if there is not a new row (at the end of the rowset*) the change should have occured in the same row //* this tests assumes the new row was placed at the end of the rowset or stayed put (**), odbc makes no promises where this row should be loacted //**this probally will stay put if the unique index is not the key in the keyset cursor from the driver becuase then the change will be an update and not an insert/delete { if(g_fOWNINSERT) { fNewRow=FALSE; //call IRowsetLocate to retrieve the change row if(!CHECK(m_pIRowsetLocate->GetRowsAt(NULL,NULL,1,pBkmrkFRST,1,1,&cRows, &pHRow3),S_OK)) { goto END; } //IsSameRow should return S_OK if(!CHECK(m_pIRowsetIdentity->IsSameRow(*pHRow2, *pHRow3),S_OK)) { goto END; } //binary comparision if(!CompareHandlesByLiteral(*pHRow2, *pHRow3,FALSE,TRUE)) { goto END; } } } //Restart the position to the begining of the rowset hr = m_pIRowset->RestartPosition(NULL); if (S_OK!=hr && DB_S_COMMANDREEXECUTED!=hr) { goto END; } //try to get the row again if(!CHECK(m_pIRowset->GetNextRows(NULL,1,1,&cRows,&pHRow3),S_OK)) goto END; //if a new row was inserted at the end of the rowset there should be a //hole (deleted row) where the row used to be. if(fNewRow) { //can test see deletes if (g_fOWNUPDATEDELETE) { if (g_fREMOVEDELETED) { //deleted row is gone, so different row will compare as S_FALSE CHECK(m_pIRowsetIdentity->IsSameRow(*pHRow3, *pHRow2),S_FALSE); //binary comparision if(!CompareHandlesByLiteral(*pHRow3, *pHRow2,FALSE,FALSE)) { goto END; } } else { //S_OK, both are the deleted row CHECK(m_pIRowsetIdentity->IsSameRow(*pHRow3, *pHRow2),S_OK); //binary comparision if(!CompareHandlesByLiteral(*pHRow3, *pHRow2,FALSE,TRUE)) { goto END; } } } else { //deletes are not visible so the test should see //the original row CHECK(m_pIRowsetIdentity->IsSameRow(*pHRow3, *pHRow2),S_OK); //binary comparision if(!CompareHandlesByLiteral(*pHRow3, *pHRow2,FALSE,TRUE)) { goto END; } } } //row stayed the same and just the value changed else { //S_OK CHECK(m_pIRowsetIdentity->IsSameRow(*pHRow3, *pHRow2),S_OK); //binary comparision if(!CompareHandlesByLiteral(*pHRow3, *pHRow2,FALSE,TRUE)) { goto END; } } //release the row handles CHECK(ReleaseRows(1, &pHRow3, TRUE),S_OK); pHRow3=NULL; CHECK(ReleaseRows(1, &pHRow2, TRUE),S_OK); pHRow2=NULL; CHECK(ReleaseRows(1, &pHRow1, TRUE),S_OK); pHRow1=NULL; //Restart the position to the begining of the rowset hr = m_pIRowset->RestartPosition(NULL); if (S_OK!=hr && DB_S_COMMANDREEXECUTED!=hr) { goto END; } //try to get the row again if(!CHECK(m_pIRowset->GetNextRows(NULL,1,1,&cRows,&pHRow3),S_OK)) goto END; //if a new row was inserted at the end of the rowset there should be a //hole where the row used to be. if(fNewRow) { //pHRow3 should be a deleted row if(!CHECK(m_pIRowsetIdentity->IsSameRow(*pHRow3, *pHRowNext),DB_E_DELETEDROW)) { goto END; } //binary comparision if(!CompareHandlesByLiteral(*pHRow3, *pHRowNext,FALSE,FALSE)) { goto END; } fTestPass=TRUE; } else { //these should not be the same rows if(!CHECK(m_pIRowsetIdentity->IsSameRow(*pHRow3, *pHRowNext),S_FALSE)) { goto END; } //binary comparision if(!CompareHandlesByLiteral(*pHRow3, *pHRowNext,FALSE,FALSE)) { goto END; } fTestPass=TRUE; } END: if(pHRowLast1) CHECK(ReleaseRows(1, &pHRowLast1, TRUE),S_OK); if(pHRow2) CHECK(ReleaseRows(1, &pHRow2, TRUE),S_OK); if(pHRow3) CHECK(ReleaseRows(1, &pHRow3, TRUE),S_OK); if(pHRowNext) CHECK(ReleaseRows(1, &pHRowNext, TRUE),S_OK); if(pHRowLast2) CHECK(ReleaseRows(1, &pHRowLast2, TRUE),S_OK); if(pHRow1) CHECK(ReleaseRows(1, &pHRow1, TRUE),S_OK); if(pData2) PROVIDER_FREE(pData2); if(fTestPass) return TEST_PASS; else return TEST_FAIL; } // }} // {{ TCW_VAR_PROTOTYPE(6) //*----------------------------------------------------------------------- // @mfunc Insert a new row into the rowset Update // // @rdesc TEST_PASS or TEST_FAIL // int Keyset_Cursor_Buffered::Variation_6() { HROW HRow = NULL; HROW *pHRow = NULL; DBCOUNTITEM cRows = 0; BYTE *pData = NULL; BOOL fTestPass = FALSE; HRESULT hr; BOOL fFound = FALSE; //Restart the position to the begining of the rowset hr = m_pIRowset->RestartPosition(NULL); if (S_OK!=hr && DB_S_COMMANDREEXECUTED!=hr) { goto END; } //Create an accessor if(!GetAccessorOnRowset(ON_ROWSET_ACCESSOR, DBACCESSOR_ROWDATA, DBPART_VALUE|DBPART_STATUS|DBPART_LENGTH, UPDATEABLE_COLS_BOUND)) goto END; if(!CHECK(InsertOneRow(g_ulNextRow++, &HRow),S_OK)) goto END; //if can't see this insert then skip if (g_fRETURNPENDINGINSERTS&&g_fOWNINSERT&&g_fLITERALIDENITIY) { if(!(pData=(BYTE*)PROVIDER_ALLOC(m_cRowSize))) goto END; //get a data buffer with the inserted data if(!CHECK(FillInputBindings(m_pTable,DBACCESSOR_ROWDATA,m_cBinding,m_rgBinding, &pData,g_ulNextRow++,m_cRowsetCols,m_rgTableColOrds, PRIMARY),S_OK)) { goto END; } //Get a row handle while (S_OK==(hr = m_pIRowset->GetNextRows(NULL,0,1,&cRows, &pHRow)) || hr == DB_S_ENDOFROWSET ) { if( cRows ==0) break; //Get the data for the ith row handle if(!CHECK(m_pIRowset->GetData(*pHRow,m_hAccessor,m_pData),S_OK)) { goto END; } //make sure GetData should be able to see the change if(CompareBuffer(m_pData,pData,m_cBinding,m_rgBinding,m_pIMalloc,TRUE,FALSE,COMPARE_ONLY)==TRUE) { fFound=TRUE; break; } if(!CHECK(m_pIRowset->ReleaseRows(1,pHRow,NULL,NULL,NULL),S_OK)) { goto END; } PROVIDER_FREE(pHRow); } //the inserted row has to be found if (!fFound) { goto END; } //IsSameRow should return DB_E_NEWLYINSERTED if DBPROP_STRONGIDENTITY //is VARIANT_FALSE only after the data has been transmitted to the back end //S_OK should be returned if(!CHECK(m_pIRowsetIdentity->IsSameRow(HRow, *pHRow),S_OK)) { goto END; } //binary comparision if(!CompareHandlesByLiteral(HRow, *pHRow,FALSE,TRUE)) { goto END; } //Update the insertion to the back end if(!CHECK(UpdateRows(1,&HRow),S_OK)) { goto END; } //IsSameRow should return DB_E_NEWLYINSERTED if DBPROP_STRONGIDENTITY //is VARIANT_FALSE if(!g_fSTRONGIDENTITY) { m_hr=m_pIRowsetIdentity->IsSameRow(HRow, *pHRow); if(m_hr!=ResultFromScode(DB_E_NEWLYINSERTED)) { goto END; } //binary comparision if(CompareHandlesByLiteral(HRow, *pHRow,FALSE,TRUE)) { goto END; } } else //S_OK should be returned { if(!CHECK(m_pIRowsetIdentity->IsSameRow(HRow, *pHRow),S_OK)) { goto END; } //binary comparision if(!CompareHandlesByLiteral(HRow, *pHRow,FALSE,TRUE)) { goto END; } } } else { fTestPass=TEST_SKIPPED; } END: if(HRow) CHECK(m_pIRowset->ReleaseRows(1,&HRow, NULL, NULL, NULL),S_OK); if(pHRow) CHECK(ReleaseRows(1, &pHRow, TRUE),S_OK); if(pData) PROVIDER_FREE(pData); if(fTestPass) return TEST_PASS; else return TEST_FAIL; } // }} // {{ TCW_VAR_PROTOTYPE(7) //*----------------------------------------------------------------------- // @mfunc Soft deleted the 1st row handle. // // @rdesc TEST_PASS or TEST_FAIL // int Keyset_Cursor_Buffered::Variation_7() { HROW *pHRow0 = NULL; HROW *pHRow1 = NULL; HROW *pHRow2 = NULL; HROW *pHRow1AfterDel = NULL; DBCOUNTITEM cRows = 0; BOOL fTestPass = FALSE; DBROWSTATUS *pDBRowStatus = NULL; BOOL fPending = TRUE; void *pData1 = NULL; void *pData2 = NULL; HRESULT hr; if(!(pData1=(BYTE*)PROVIDER_ALLOC(m_cRowSize))) goto END; if(!(pData2=(BYTE*)PROVIDER_ALLOC(m_cRowSize))) goto END; //Restart the position to the begining of the rowset hr = m_pIRowset->RestartPosition(NULL); if (S_OK!=hr && DB_S_COMMANDREEXECUTED!=hr) { goto END; } //get a row handle if(!CHECK(m_pIRowset->GetNextRows(NULL,3,1,&cRows,&pHRow0),S_OK)) goto END; //get the next row handle if(!CHECK(m_pIRowset->GetNextRows(NULL,0,1,&cRows,&pHRow1),S_OK)) goto END; //get the data for the row if(!CHECK(m_pIRowset->GetData(*pHRow1, m_hAccessor, pData1),S_OK)) goto END; //get the next row handle if(!CHECK(m_pIRowset->GetNextRows(NULL,0,1,&cRows,&pHRow2),S_OK)) goto END; //soft delete the 2nd row if(!CHECK(DeleteRows(1,pHRow1),S_OK)) goto END; //try to get the 2nd row again, pending delete might or might not be there //if it is there this will fetch it, if it is not there this will fetch the first row if(!CHECK(m_pIRowset->GetNextRows(NULL,-2,1,&cRows,&pHRow1AfterDel),S_OK)) goto END; //determine through props which row was fetched and check it //if test doesn't see its own deletes the first row should have been fetched if (!g_fOWNUPDATEDELETE) { //IsSameRow should return S_OK. if(!CHECK(m_pIRowsetIdentity->IsSameRow(*pHRow1, *pHRow1AfterDel),S_OK)) { goto END; } //binary comparision, if(!CompareHandlesByLiteral(*pHRow1, *pHRow1AfterDel,FALSE,TRUE)) { goto END; } //so look at buffer just for fun if(!CHECK(m_pIRowset->GetData(*pHRow1AfterDel, m_hAccessor, pData2),S_OK)) goto END; //since OWNUPDATEDELETE is FALSE these do compare, delete is not seen if(!CompareBuffer(pData1,pData2,m_cBinding,m_rgBinding,m_pIMalloc,TRUE,FALSE,COMPARE_ONLY)==TRUE) { goto END; } } else { if (g_fLITERALIDENITIY&&g_fREMOVEDELETED) { //IsSameRow should return S_FALSE. if(!CHECK(m_pIRowsetIdentity->IsSameRow(*pHRow1, *pHRow1AfterDel),S_FALSE)) { goto END; } //binary comparision, if(!CompareHandlesByLiteral(*pHRow1, *pHRow1AfterDel,FALSE,FALSE)) { goto END; } //IsSameRow should return S_OK first row fetched and new fetch because the deleted row is removed if(!CHECK(m_pIRowsetIdentity->IsSameRow(*pHRow0, *pHRow1AfterDel),S_OK)) { goto END; } //binary comparision, these rows can compare literally if(!CompareHandlesByLiteral(*pHRow0, *pHRow1AfterDel,FALSE,TRUE)) { goto END; } } else { //IsSameRow should return DB_E_DELETEDROW the deleted row is not removed which is //pointed to by pHRow1AfterDel //IsSameRow should return S_OK. if(!CHECK(m_pIRowsetIdentity->IsSameRow(*pHRow1, *pHRow1AfterDel),S_OK)) { goto END; } //binary comparision, if(!CompareHandlesByLiteral(*pHRow1, *pHRow1AfterDel,FALSE,TRUE)) { goto END; } } } //Update the data, deletes are no longer pending if(!CHECK(UpdateRows(1,pHRow1,&pDBRowStatus),S_OK)) goto END; //IsSameRow should return DB_E_DELETEDROW because pHRow1 points to a deleted //row no matter what DBPROP_REMOVEDELETED has for a default if(!CHECK(m_pIRowsetIdentity->IsSameRow(*pHRow1, *pHRow1AfterDel),DB_E_DELETEDROW)) { goto END; } if (g_fREMOVEDELETED) { //IsSameRow should return S_OK because the deleted row is removed if(!CHECK(m_pIRowsetIdentity->IsSameRow(*pHRow0, *pHRow1AfterDel),S_OK)) { goto END; } //binary comparision, these rows can compare literally if(!CompareHandlesByLiteral(*pHRow0, *pHRow1AfterDel,FALSE,TRUE)) { goto END; } } else { //IsSameRow should return DB_E_DELETEDROW the deleted row is not removed which is //pointed to by pHRow1AfterDel if(!CHECK(m_pIRowsetIdentity->IsSameRow(*pHRow0, *pHRow1AfterDel),DB_E_DELETEDROW)) { goto END; } //binary comparision if(!CompareHandlesByLiteral(*pHRow0, *pHRow1AfterDel,FALSE,FALSE)) { goto END; } } fTestPass = TRUE; END: //undo the deletions if(pHRow0) { CHECK(ReleaseRows(1, &pHRow0,TRUE),S_OK); } //undo the deletions if(pHRow1) { CHECK(ReleaseRows(1, &pHRow1,TRUE),S_OK); } //undo the deletions if(pHRow2) { CHECK(ReleaseRows(1, &pHRow2,TRUE),S_OK); } if(pData1) ReleaseInputBindingsMemory(m_cBinding, m_rgBinding,(BYTE *)pData1,FALSE); if(pData2) ReleaseInputBindingsMemory(m_cBinding, m_rgBinding,(BYTE *)pData2,TRUE); if(pHRow1AfterDel) CHECK(ReleaseRows(1, &pHRow1AfterDel,TRUE),S_OK); if(pDBRowStatus) PROVIDER_FREE(pDBRowStatus); if(fTestPass) return TEST_PASS; else return TEST_FAIL; } // }} // }} // {{ TCW_TERMINATE_METHOD //-------------------------------------------------------------------- // @mfunc TestCase Termination Routine // // @rdesc TRUE or FALSE // BOOL Keyset_Cursor_Buffered::Terminate() { ReleaseRowsetAndAccessor(); // {{ TCW_TERM_BASECLASS_CHECK2 return(TCIRowsetIdentity::Terminate()); } // }} // }} // {{ TCW_TC_PROTOTYPE(Dynamic_Query_Buffered) //*----------------------------------------------------------------------- //| Test Case: Dynamic_Query_Buffered - Dynamic_Query_Buffered //| Created: 05/28/96 //*----------------------------------------------------------------------- //-------------------------------------------------------------------- // @mfunc TestCase Initialization Routine // // @rdesc TRUE or FALSE // BOOL Dynamic_Query_Buffered::Init() { DBPROPID rgGuid[7]; BOOL fCursorNotSupported=FALSE; ULONG cProp = g_MSDASQL?7:6; rgGuid[0]=DBPROP_IRowsetIdentity; rgGuid[1]=DBPROP_IRowsetChange; rgGuid[2]=DBPROP_OTHERINSERT; rgGuid[3]=DBPROP_OTHERUPDATEDELETE; rgGuid[4]=DBPROP_IRowsetUpdate; rgGuid[5]=DBPROP_CANHOLDROWS; rgGuid[6]=KAGPROP_QUERYBASEDUPDATES; if(!TCIRowsetIdentity::Init()) return FALSE; //check to see if the execute is going to fail if( !g_rgDBPrpt[IDX_ScrollBackwards].fSupported || !g_rgDBPrpt[IDX_CanHoldRows].fSupported || !g_rgDBPrpt[IDX_OtherInsert].fSupported ) { fCursorNotSupported = TRUE; odtLog << L"The Provider does not support a DYNAMIC Cursor.\n"; } //get a rowset with IRowsetIdentity, with Dynamic Cursor if(!GetRowsetAndAccessor(USE_OPENROWSET, cProp, rgGuid,0,NULL,NO_ACCESSOR)) { return TEST_SKIPPED; } if (!g_fTestValid) { return TRUE; } //has to be dynamic cursor if(GetCursorType()==DYNAMIC_CURSOR) { odtLog << L"This test will continue but a dynamic cursor was not obtained.\n"; // return FALSE; } return TRUE; } // {{ TCW_VAR_PROTOTYPE(1) //*----------------------------------------------------------------------- // @mfunc Soft-delete one row. S_FALSE. Call IRowsetUpdate::Update. DB_E_DELETEDROW. // // @rdesc TEST_PASS or TEST_FAIL // int Dynamic_Query_Buffered::Variation_1() { HROW *pHRow0 = NULL; HROW *pHRow1 = NULL; HROW *pHRow2 = NULL; HROW *pHRow1AfterDel = NULL; DBCOUNTITEM cRows = 0; BOOL fTestPass = FALSE; DBROWSTATUS *pDBRowStatus = NULL; BOOL fPending = TRUE; void *pData1 = NULL; void *pData2 = NULL; if(!(pData1=(BYTE*)PROVIDER_ALLOC(m_cRowSize))) goto END; if(!(pData2=(BYTE*)PROVIDER_ALLOC(m_cRowSize))) goto END; //get a row handle if(!CHECK(m_pIRowset->GetNextRows(NULL,0,1,&cRows,&pHRow0),S_OK)) goto END; //get the next row handle if(!CHECK(m_pIRowset->GetNextRows(NULL,0,1,&cRows,&pHRow1),S_OK)) goto END; //get the data for the row if(!CHECK(m_pIRowset->GetData(*pHRow1, m_hAccessor, pData1),S_OK)) goto END; //get the next row handle if(!CHECK(m_pIRowset->GetNextRows(NULL,0,1,&cRows,&pHRow2),S_OK)) goto END; //soft delete the 2nd row if(!CHECK(DeleteRows(1,pHRow1),S_OK)) goto END; //try to get the 2nd row again, pending delete might or might not be there //if it is there this will fetch it, if it is not there this will fetch the first row if(!CHECK(m_pIRowset->GetNextRows(NULL,-2,1,&cRows,&pHRow1AfterDel),S_OK)) goto END; //determine through props which row was fetched and check it //if test doesn't see its own deletes the first row should have been fetched if (!g_fOWNUPDATEDELETE) { //IsSameRow should return S_FALSE. if(!CHECK(m_pIRowsetIdentity->IsSameRow(*pHRow1, *pHRow1AfterDel),S_FALSE)) { goto END; } //binary comparision, if(!CompareHandlesByLiteral(*pHRow1, *pHRow1AfterDel,FALSE,FALSE)) { goto END; } //so look at buffer just for fun if(!CHECK(m_pIRowset->GetData(*pHRow1AfterDel, m_hAccessor, pData2),S_OK)) goto END; //since OWNUPDATEDELETE is FALSE these do not compare, delete is not seen if(CompareBuffer(pData1,pData2,m_cBinding,m_rgBinding,m_pIMalloc,TRUE,FALSE,COMPARE_ONLY)==TRUE) { goto END; } } else { if (g_fLITERALIDENITIY&&g_fREMOVEDELETED) { //IsSameRow should return S_FALSE. if(!CHECK(m_pIRowsetIdentity->IsSameRow(*pHRow1, *pHRow1AfterDel),S_FALSE)) { goto END; } //binary comparision, if(!CompareHandlesByLiteral(*pHRow1, *pHRow1AfterDel,FALSE,FALSE)) { goto END; } //IsSameRow should return S_OK first row fetched and new fetch because the deleted row is removed if(!CHECK(m_pIRowsetIdentity->IsSameRow(*pHRow0, *pHRow1AfterDel),S_OK)) { goto END; } //binary comparision, these rows can compare literally if(!CompareHandlesByLiteral(*pHRow0, *pHRow1AfterDel,FALSE,TRUE)) { goto END; } } else { //IsSameRow should return DB_E_DELETEDROW the deleted row is not removed which is //pointed to by pHRow1AfterDel //IsSameRow should return S_OK. if(!CHECK(m_pIRowsetIdentity->IsSameRow(*pHRow1, *pHRow1AfterDel),S_OK)) { goto END; } //binary comparision, if(!CompareHandlesByLiteral(*pHRow1, *pHRow1AfterDel,FALSE,TRUE)) { goto END; } } } //Update the data, deletes are no longer pending if(!CHECK(UpdateRows(1,pHRow1,&pDBRowStatus),S_OK)) goto END; //IsSameRow should return DB_E_DELETEDROW because pHRow1 points to a deleted //row no matter what DBPROP_REMOVEDELETED has for a default if(!CHECK(m_pIRowsetIdentity->IsSameRow(*pHRow1, *pHRow1AfterDel),DB_E_DELETEDROW)) { goto END; } //binary comparision, these rows can't possibly compare literally if(!CompareHandlesByLiteral(*pHRow1, *pHRow1AfterDel,FALSE,FALSE)) { goto END; } if (g_fREMOVEDELETED) { //IsSameRow should return S_OK because the deleted row is removed if(!CHECK(m_pIRowsetIdentity->IsSameRow(*pHRow0, *pHRow1AfterDel),S_OK)) { goto END; } //binary comparision, these rows can compare literally if(!CompareHandlesByLiteral(*pHRow0, *pHRow1AfterDel,FALSE,TRUE)) { goto END; } } else { //IsSameRow should return DB_E_DELETEDROW the deleted row is not removed which is //pointed to by pHRow1AfterDel if(!CHECK(m_pIRowsetIdentity->IsSameRow(*pHRow0, *pHRow1AfterDel),DB_E_DELETEDROW)) { goto END; } //binary comparision if(!CompareHandlesByLiteral(*pHRow0, *pHRow1AfterDel,FALSE,FALSE)) { goto END; } } fTestPass = TRUE; END: //undo the deletions if(pHRow0) { CHECK(ReleaseRows(1, &pHRow0,TRUE),S_OK); } //undo the deletions if(pHRow1) { CHECK(ReleaseRows(1, &pHRow1,TRUE),S_OK); } //undo the deletions if(pHRow2) { CHECK(ReleaseRows(1, &pHRow2,TRUE),S_OK); } if(pData1) ReleaseInputBindingsMemory(m_cBinding, m_rgBinding,(BYTE *)pData1,FALSE); if(pData2) ReleaseInputBindingsMemory(m_cBinding, m_rgBinding,(BYTE *)pData2,TRUE); if(pHRow1AfterDel) CHECK(ReleaseRows(1, &pHRow1AfterDel,TRUE),S_OK); if(pDBRowStatus) PROVIDER_FREE(pDBRowStatus); if(fTestPass) return TEST_PASS; else return TEST_FAIL; } // }} // {{ TCW_TERMINATE_METHOD //-------------------------------------------------------------------- // @mfunc TestCase Termination Routine // // @rdesc TRUE or FALSE // BOOL Dynamic_Query_Buffered::Terminate() { ReleaseRowsetAndAccessor(); return(TCIRowsetIdentity::Terminate()); } // }} // }} // {{ TCW_TC_PROTOTYPE(Dynamic_Cursor_Immediate) //*----------------------------------------------------------------------- //| Test Case: Dynamic_Cursor_Immediate - Dynamic_Cursor_Immediate //| Created: 05/28/96 //*----------------------------------------------------------------------- //-------------------------------------------------------------------- // @mfunc TestCase Initialization Routine // // @rdesc TRUE or FALSE // BOOL Dynamic_Cursor_Immediate::Init() { DBPROPID rgGuid[5]; BOOL fCursorNotSupported=FALSE; ULONG cProp = g_MSDASQL?5:4; rgGuid[0]=DBPROP_IRowsetIdentity; rgGuid[1]=DBPROP_IRowsetChange; rgGuid[2]=DBPROP_OTHERINSERT; rgGuid[3]=DBPROP_OTHERUPDATEDELETE; rgGuid[4]=KAGPROP_QUERYBASEDUPDATES; if(!TCIRowsetIdentity::Init()) return FALSE; //check to see if the execute is going to fail if( !g_rgDBPrpt[IDX_ScrollBackwards].fSupported || !g_rgDBPrpt[IDX_CanHoldRows].fSupported || !g_rgDBPrpt[IDX_OtherInsert].fSupported ) { fCursorNotSupported = TRUE; odtLog << L"The Provider does not support a DYNAMIC Cursor.\n"; } //get a rowset with IRowsetIdentity, with Dynamic Cursor if(!GetRowsetAndAccessor(USE_OPENROWSET, cProp, rgGuid,0,NULL,NO_ACCESSOR)) { return TEST_SKIPPED; } if (!g_fTestValid) { return TRUE; } //has to be dynamic cursor if(GetCursorType()==DYNAMIC_CURSOR) { odtLog << L"This test will continue but a dynamic cursor was not obtained.\n"; // return FALSE; } return TRUE; } // {{ TCW_VAR_PROTOTYPE(1) //*----------------------------------------------------------------------- // @mfunc Hard-delete one row. // // @rdesc TEST_PASS or TEST_FAIL // int Dynamic_Cursor_Immediate::Variation_1() { HROW *pHRow = NULL; DBCOUNTITEM cRows = 0; BOOL fTestPass = FALSE; //if this test variation is not valid if (!g_fTestValid) { odtLog << L"The Provider does not support the properties that are necessary for this variation to execute.\n"; return TEST_PASS; } //get two row handles if(!CHECK(m_pIRowset->GetNextRows(NULL, 8, 2, &cRows, &pHRow),S_OK)) goto END; //hard-delete the 1st row if(!CHECK(DeleteRows(1,pHRow),S_OK)) goto END; //IsSameRow should return DB_E_DELETEDROW if(!CHECK(m_pIRowsetIdentity->IsSameRow(pHRow[1], *pHRow),DB_E_DELETEDROW)) { goto END; } //binary comparision if(CompareHandlesByLiteral(pHRow[1], *pHRow,FALSE,FALSE)) { fTestPass=TRUE; } END: if(pHRow) { CHECK(m_pIRowset->ReleaseRows(2,pHRow,NULL,NULL,NULL),S_OK); PROVIDER_FREE(pHRow); } if(fTestPass) return TEST_PASS; else return TEST_FAIL; } // }} // }} // {{ TCW_TERMINATE_METHOD //-------------------------------------------------------------------- // @mfunc TestCase Termination Routine // // @rdesc TRUE or FALSE // BOOL Dynamic_Cursor_Immediate::Terminate() { ReleaseRowsetAndAccessor(); return(TCIRowsetIdentity::Terminate()); } // }} // }} // {{ TCW_TC_PROTOTYPE(ExtendedErrors) //*----------------------------------------------------------------------- //| Test Case: ExtendedErrors - Extended Errors //| Created: 07/15/96 //*----------------------------------------------------------------------- //-------------------------------------------------------------------- // @mfunc TestCase Initialization Routine // // @rdesc TRUE or FALSE // BOOL ExtendedErrors::Init() { DBPROPID rgGuid[2]; ULONG cProp=1; rgGuid[0]=DBPROP_IRowsetIdentity; if(g_rgDBPrpt[IDX_IRowsetChange].fSupported) { rgGuid[1]=DBPROP_IRowsetChange; cProp=2; } if(!TCIRowsetIdentity::Init()) return FALSE; //get a rowset with IID_IRowsetIdentity if(! GetRowsetAndAccessor(USE_OPENROWSET, cProp,rgGuid,0,NULL,NO_ACCESSOR)) return FALSE; else return TRUE; } // {{ TCW_VAR_PROTOTYPE(1) //*----------------------------------------------------------------------- // @mfunc Valid IRowsetIdentity calls with previous error object existing. // // @rdesc TEST_PASS or TEST_FAIL // int ExtendedErrors::Variation_1() { HROW HRow = NULL; HROW *pHRow = &HRow; DBCOUNTITEM cRows = 0; BOOL fTestPass = FALSE; //if this test variation is not valid if (!g_fTestValid) { odtLog << L"The Provider does not support the properties that are necessary for this variation to execute.\n"; return TEST_PASS; } //For each method of the interface, first create an error object on //the current thread, try get a success from the IRowsetIdentity method. //We then check extended errors to verify the right extended error behavior. //get one row handles if(!CHECK(m_pIRowset->GetNextRows(NULL,1,1,&cRows,&pHRow),S_OK)) goto END; m_pExtError->CauseError(); //IsSameRow should return S_OK if(CHECK(m_hr=m_pIRowsetIdentity->IsSameRow(HRow,HRow),S_OK)) //Do extended check following IsSameRow fTestPass = XCHECK(m_pIRowsetIdentity, IID_IRowsetIdentity, m_hr); END: if(HRow) CHECK(m_pIRowset->ReleaseRows(1, pHRow, NULL,NULL,NULL),S_OK); if(fTestPass) return TEST_PASS; else return TEST_FAIL; } // }} // {{ TCW_VAR_PROTOTYPE(2) //*----------------------------------------------------------------------- // @mfunc Invalid IRowsetIdentity calls with previous error object existing // // @rdesc TEST_PASS or TEST_FAIL // int ExtendedErrors::Variation_2() { HROW *pHRow = NULL; DBCOUNTITEM cRows = 0; BOOL fTestPass = FALSE; //if this test variation is not valid if (!g_fTestValid) { odtLog << L"The Provider does not support the properties that are necessary for this variation to execute.\n"; return TEST_PASS; } //For each method of the interface, first create an error object on //the current thread, try get a failure from the IRowsetIdentity method. //We then check extended errors to verify the right extended error behavior. //get two row handles if(!CHECK(m_pIRowset->GetNextRows(NULL,0,2,&cRows,&pHRow),S_OK)) goto END; //release the 2nd row handle if(!CHECK(m_pIRowset->ReleaseRows(1,&(pHRow[1]),NULL,NULL,NULL),S_OK)) goto END; pHRow[1]=NULL; //mark the active row handles cRows--; m_pExtError->CauseError(); //IsSameRow should return DB_E_BADROWHANDLE if(CHECK(m_hr=m_pIRowsetIdentity->IsSameRow(pHRow[1], *pHRow),DB_E_BADROWHANDLE)) //Do extended check following IsSameRow fTestPass = XCHECK(m_pIRowsetIdentity, IID_IRowsetIdentity, m_hr); END: if(pHRow) { CHECK(m_pIRowset->ReleaseRows(cRows, pHRow, NULL,NULL,NULL),S_OK); PROVIDER_FREE(pHRow); } if(fTestPass) return TEST_PASS; else return TEST_FAIL; } // }} // {{ TCW_VAR_PROTOTYPE(3) //*----------------------------------------------------------------------- // @mfunc Invalid IRowsetIdentity calls with no previous error object existing // // @rdesc TEST_PASS or TEST_FAIL // int ExtendedErrors::Variation_3() { HROW *pHRow = NULL; DBCOUNTITEM cRows = 0; DBROWSTATUS rgRowStatus[1]; BOOL fTestPass = FALSE; if(g_fReadOnlyProvider) return TEST_PASS; //if this test variation is not valid if (!g_fTestValid) { odtLog << L"The Provider does not support the properties that are necessary for this variation to execute.\n"; return TEST_PASS; } //if IRowsetChange not available because conformance won't allow it if (!g_fIRowsetChange) { odtLog << L"Can not get to IRowsetChange, can not insert a row.\n"; return TEST_PASS; } //if IRowsetChange not available because conformance won't allow it //For read only provider or IRowsetChange not available, skip this variation if(g_fReadOnlyProvider || !(g_fROWSETUPDATABLE)) { odtLog << L"Can not get to IRowsetChange, can not insert a row.\n"; return TEST_PASS; } //For each method of the interface, with no error object on //the current thread, try get a failure from the IRowsetIdentity method. //We then check extended errors to verify the right extended error behavior. //get two row handles if(!CHECK(m_pIRowset->GetNextRows(NULL,0,2,&cRows,&pHRow),S_OK)) goto END; //For read only provider or IRowsetChange not available, skip this variation if(g_fReadOnlyProvider || !(g_fROWSETUPDATABLE)) { odtLog << L"Can not get to IRowsetChange, can not insert a row.\n"; return TEST_PASS; } //check to see if the DSO is ReadOnly if( IsPropertySet(DBPROPSET_DATASOURCEINFO, DBPROP_DATASOURCEREADONLY, NULL, 0) ) { //try deleting the row handle if(!CHECK(m_hr=m_pIRowsetChange->DeleteRows(NULL,1,pHRow,rgRowStatus),DB_E_ERRORSOCCURRED) || !COMPARE(rgRowStatus[0], DBROWSTATUS_E_PERMISSIONDENIED)) goto END; //Do extended check following IsSameRow fTestPass = XCHECK(m_pIRowsetChange, IID_IRowsetChange, m_hr); //IsSameRow should return S_OK CHECK(m_pIRowsetIdentity->IsSameRow(*pHRow,pHRow[0]),S_OK); } else { //delete the row handle if(!CHECK(m_pIRowsetChange->DeleteRows(NULL,1,pHRow,rgRowStatus),S_OK) || !COMPARE(rgRowStatus[0], DBROWSTATUS_S_OK)) goto END; //IsSameRow should return DB_E_DELETEDROW CHECK(m_hr=m_pIRowsetIdentity->IsSameRow(*pHRow, pHRow[0]),DB_E_DELETEDROW); //Do extended check following IsSameRow fTestPass = XCHECK(m_pIRowsetIdentity, IID_IRowsetIdentity, m_hr); } END: if(pHRow) { CHECK(m_pIRowset->ReleaseRows(2, pHRow, NULL,NULL,NULL),S_OK); PROVIDER_FREE(pHRow); } if(fTestPass) return TEST_PASS; else return TEST_FAIL; } // }} // {{ TCW_TERMINATE_METHOD //-------------------------------------------------------------------- // @mfunc TestCase Termination Routine // // @rdesc TRUE or FALSE // BOOL ExtendedErrors::Terminate() { ReleaseRowsetAndAccessor(); // {{ TCW_TERM_BASECLASS_CHECK2 return(TCIRowsetIdentity::Terminate()); } // }} // }}