8659 lines
229 KiB
C++
8659 lines
229 KiB
C++
//--------------------------------------------------------------------
|
|
// Microsoft OLE DB Test
|
|
//
|
|
// Copyright 1996-2000 Microsoft Corporation.
|
|
//
|
|
// @doc
|
|
//
|
|
// @module itrnjoin.CPP | Test Module for Joined Transactions
|
|
//
|
|
#include "modstandard.hpp"
|
|
#define DBINITCONSTANTS // Must be defined to initialize constants in OLEDB.H
|
|
#define INITGUID
|
|
#include "itrnjoin.h"
|
|
#include "txnbase.hpp" //Base classes for transacted rowsets
|
|
//#ifdef TXNJOIN
|
|
#include "XOLEHLP.H"
|
|
#include "txdtc.h"
|
|
//#endif //TXNJOIN
|
|
|
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Module Values
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
|
|
// {{ TCW_MODULE_GLOBALS
|
|
DECLARE_MODULE_CLSID = { 0x561a4720, 0x9dbd, 0x11d1, { 0x87, 0x30, 0x00, 0xc0, 0x4f, 0xd6, 0x58, 0xf5 }};
|
|
DECLARE_MODULE_NAME("ITransactionJoin");
|
|
DECLARE_MODULE_OWNER("Microsoft");
|
|
DECLARE_MODULE_DESCRIP("Test Module for Joined Transactions");
|
|
DECLARE_MODULE_VERSION(839560026);
|
|
// }}
|
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Global Values
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
|
|
//This must be defined so that the base class constructors
|
|
//in txnbase.hpp know what to use for this test module's name.
|
|
LPWSTR gwszThisModuleName = L"itrnjoin";
|
|
BOOL gfDTCStarted = FALSE;
|
|
BOOL gfBlocked = FALSE;
|
|
|
|
|
|
//--------------------------------------------------------------------
|
|
// @func Module level initialization routine
|
|
//
|
|
// @rdesc Success or Failure
|
|
// @flag TRUE | Successful initialization
|
|
// @flag FALSE | Initialization problems
|
|
//
|
|
BOOL ModuleInit(CThisTestModule *pThisTestModule)
|
|
{
|
|
HRESULT hr;
|
|
ITransactionJoin *pITxnJoin = NULL;
|
|
|
|
WCHAR lpService[10] = L"MSDTC";
|
|
BOOL fCPPass = FALSE;
|
|
SC_HANDLE hService;
|
|
SC_HANDLE hServiceDTC;
|
|
WCHAR *pwszDBMS;
|
|
WCHAR *pwszDBMSVer;
|
|
|
|
|
|
|
|
if (ModuleCreateDBSession(pThisTestModule))
|
|
{
|
|
//make sure DTC is started
|
|
//this will fail if dtc is already started. no big
|
|
//the only concern here is that dtc is started
|
|
hService=OpenSCManager (NULL,NULL,SC_MANAGER_ALL_ACCESS);
|
|
|
|
//if this fails, let the test proceed, this could be a win98 machine with a remote DTC which doesn't
|
|
//appear as a service
|
|
if (hService)
|
|
{
|
|
hServiceDTC=OpenServiceW(hService, lpService,SERVICE_START);
|
|
fCPPass=StartService(hServiceDTC,NULL,NULL);
|
|
//if this fails remember it was because the service was already running
|
|
//or DTC is not working
|
|
if(!fCPPass)
|
|
{
|
|
if (ERROR_SERVICE_ALREADY_RUNNING==GetLastError())
|
|
{
|
|
gfDTCStarted=TRUE;
|
|
}
|
|
else
|
|
{
|
|
odtLog <<L"A useable MSDTC is not on this machine.\n";
|
|
return TEST_SKIPPED;
|
|
}
|
|
}
|
|
CloseServiceHandle(hServiceDTC);
|
|
CloseServiceHandle(hService);
|
|
}
|
|
|
|
//Fail gracefully and quit module if we don't support local transactions
|
|
if (SUCCEEDED(hr = pThisTestModule->m_pIUnknown2->QueryInterface(
|
|
IID_ITransactionJoin, (void **)&pITxnJoin)))
|
|
{
|
|
pITxnJoin->Release();
|
|
pITxnJoin = NULL;
|
|
}
|
|
else
|
|
{
|
|
//Make sure we returned E_NOINTERFACE if we've failed
|
|
if (pThisTestModule->m_pError->Validate(hr,
|
|
LONGSTRING(__FILE__), __LINE__, E_NOINTERFACE))
|
|
{
|
|
odtLog <<L"ITransactionJoin is not supported.\n";
|
|
}
|
|
return TEST_SKIPPED;
|
|
}
|
|
|
|
//Create a table we'll use for the whole test module,
|
|
//store it in pVoid for now
|
|
pThisTestModule->m_pVoid = new CTable(
|
|
(IUnknown *)pThisTestModule->m_pIUnknown2,
|
|
(LPWSTR)gwszModuleName
|
|
);
|
|
|
|
if (!pThisTestModule->m_pVoid)
|
|
{
|
|
odtLog << wszMemoryAllocationError;
|
|
return FALSE;
|
|
}
|
|
|
|
//Start with a table with rows
|
|
if (FAILED(((CTable *)pThisTestModule->m_pVoid)->CreateTable(NUM_ROWS)))
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
//Init last actual insert number to last row we inserted
|
|
g_ulLastActualInsert = NUM_ROWS;
|
|
|
|
//First row in table is 1
|
|
g_ulFirstRowInTable = 1;
|
|
|
|
g_ulLastActualDelete = 0;
|
|
|
|
|
|
GetProperty(DBPROP_DBMSVER ,DBPROPSET_DATASOURCEINFO, (IUnknown *)pThisTestModule->m_pIUnknown,&pwszDBMSVer);
|
|
GetProperty(DBPROP_DBMSNAME ,DBPROPSET_DATASOURCEINFO, (IUnknown *)pThisTestModule->m_pIUnknown,&pwszDBMS);
|
|
|
|
//if this is SQL Server with a version less than 8 flag is so some variations can be skipped
|
|
//becasue they will block.
|
|
if (!wcscmp(pwszDBMS,L"Microsoft SQL Server"))
|
|
{
|
|
if(wcscmp(pwszDBMSVer,L"08.00.0000") < 0)
|
|
{
|
|
gfBlocked = TRUE;
|
|
}
|
|
}
|
|
PROVIDER_FREE(pwszDBMS);
|
|
PROVIDER_FREE(pwszDBMSVer);
|
|
|
|
//If we made it this far, everything has succeeded
|
|
return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
//--------------------------------------------------------------------
|
|
// @func Module level termination routine
|
|
//
|
|
// @rdesc Success or Failure
|
|
// @flag TRUE | Successful initialization
|
|
// @flag FALSE | Initialization problems
|
|
//
|
|
BOOL ModuleTerminate(CThisTestModule * pThisTestModule)
|
|
{
|
|
WCHAR lpService[20] = L"MSDTC";
|
|
BOOL fCPPass = FALSE;
|
|
SC_HANDLE hService;
|
|
SC_HANDLE hServiceDTC;
|
|
|
|
//if DTC was not started before the test then make sure it is stopped
|
|
if (!gfDTCStarted)
|
|
{
|
|
//make sure DTC is in the state it was before the test started
|
|
hService=OpenSCManager (NULL,NULL,SC_MANAGER_ALL_ACCESS);
|
|
hServiceDTC=OpenServiceW(hService, lpService,SERVICE_STOP);
|
|
fCPPass=ControlService(hServiceDTC,SERVICE_CONTROL_STOP,NULL);
|
|
CloseServiceHandle(hServiceDTC);
|
|
CloseServiceHandle(hService);
|
|
}
|
|
|
|
//We still own the table since all of our testcases
|
|
//have only used it and not deleted it.
|
|
if (pThisTestModule->m_pVoid)
|
|
{
|
|
((CTable *)pThisTestModule->m_pVoid)->DropTable();
|
|
delete (CTable*)pThisTestModule->m_pVoid;
|
|
pThisTestModule->m_pVoid = NULL;
|
|
}
|
|
|
|
return ModuleReleaseDBSession(pThisTestModule);
|
|
}
|
|
|
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Base Class Declarations
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
|
|
|
|
//--------------------------------------------------------------------
|
|
// @class CTxnChgUpdRowset | Transactable updateable buffered mode rowset
|
|
// @base public | CTxnChgRowset
|
|
//--------------------------------------------------------------------
|
|
class CTxnChgUpdRowset : public CTxnChgRowset
|
|
{
|
|
// @access public
|
|
public:
|
|
|
|
//@cmember IRowsetUpdate Interface for this rowset
|
|
IRowsetUpdate *m_pIRowsetUpdate;
|
|
//@cmember IRowset interface for this rowset
|
|
IRowset *m_pIRowset;
|
|
//@cmember Count of pending rows on update
|
|
DBCOUNTITEM m_cPendingRows;
|
|
//@cmember Array of pending rows
|
|
HROW *m_rgPendingRows;
|
|
//@cmember Array of pending rows' status
|
|
DBPENDINGSTATUS *m_rgPendingStatus;
|
|
|
|
|
|
//@cmember CTOR
|
|
CTxnChgUpdRowset(LPWSTR tcName) : CTxnChgRowset(tcName){};
|
|
//@cmember Initialization - Creates an updateable buffered mode rowset
|
|
virtual BOOL Init();
|
|
//@cmember Termination - Does termination for an updateable buffered mode rowset
|
|
virtual BOOL Terminate();
|
|
//@cmember Creates an updateable buffered rowset and gets IRowsetUpdate interface
|
|
virtual HRESULT MakeRowset();
|
|
//@cmember Frees an updateable buffered rowset and frees IRowsetUpdate interface
|
|
virtual HRESULT FreeRowset();
|
|
//@cmember make sure properties are set
|
|
virtual HRESULT ReSetProps();
|
|
//@cmember Verifies pending change after a transaction commit or abort
|
|
BOOL CheckPendingRow(ULONG cPendingRows);
|
|
};
|
|
|
|
|
|
//--------------------------------------------------------------------
|
|
// @class CUpdateTxn | Base Class for IRowsetUpdate / Transaction testing.
|
|
// @base public | CTxn
|
|
//--------------------------------------------------------------------
|
|
class CTxnUpdate : public CTxn
|
|
{
|
|
// @access public
|
|
public:
|
|
//@cmember Pointer to Rowset object that supports Changes in buffered mode
|
|
CTxnChgUpdRowset *m_pChgUpdRowset1;
|
|
//@cmember Pointer to Rowset object that supports Changes in buffered mode
|
|
CTxnChgUpdRowset *m_pChgUpdRowset2;
|
|
//@cmember CTOR
|
|
CTxnUpdate(LPWSTR tcName) : CTxn(tcName){};
|
|
//@cmember Initialization
|
|
virtual BOOL Init();
|
|
//@cmember Termination
|
|
virtual BOOL Terminate();
|
|
|
|
//@cmember Releases all rowsets associated with any encapsulated objects
|
|
virtual void ReleaseAllRowsetsAndTxns();
|
|
};
|
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Base Class Function Definitions
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
|
|
//--------------------------------------------------------------------
|
|
// Does init for buffered mode rowset.
|
|
// @mfunc Init
|
|
//--------------------------------------------------------------------
|
|
BOOL CTxnChgUpdRowset::Init()
|
|
{
|
|
const ULONG cProps = 5;
|
|
DBPROP DBProp[cProps];
|
|
DBPROPSET RowsetPropSet;
|
|
BOOL fInit = FALSE;
|
|
ULONG i = 0;
|
|
|
|
m_pIRowsetUpdate = NULL;
|
|
m_pIRowset = NULL;
|
|
m_cPendingRows = 0;
|
|
m_rgPendingRows = NULL;
|
|
m_rgPendingStatus = NULL;
|
|
|
|
//Set properties for change ability and determine support
|
|
fInit = CTxnChgRowset::Init();
|
|
|
|
if (g_rgDBPrpt[IDX_IRowsetChange].fProviderSupported)
|
|
{
|
|
//Now reset all properties and include IRowsetUpdate
|
|
DBProp[i].dwPropertyID = DBPROP_IRowsetChange;
|
|
DBProp[i].dwOptions=0;
|
|
DBProp[i].vValue.vt=VT_BOOL;
|
|
V_BOOL(&(DBProp[i].vValue))=VARIANT_TRUE;
|
|
DBProp[i].colid = DB_NULLID;
|
|
i++;
|
|
|
|
DBProp[i].dwPropertyID= DBPROP_IRowsetUpdate;
|
|
DBProp[i].dwOptions=0;
|
|
DBProp[i].vValue.vt=VT_BOOL;
|
|
DBProp[i].colid = DB_NULLID;
|
|
V_BOOL(&(DBProp[i].vValue))=VARIANT_TRUE;
|
|
i++;
|
|
|
|
DBProp[i].dwPropertyID= DBPROP_UPDATABILITY;
|
|
DBProp[i].dwOptions=0;
|
|
DBProp[i].vValue.vt=VT_I4;
|
|
DBProp[i].colid = DB_NULLID;
|
|
DBProp[i].vValue.lVal= DBPROPVAL_UP_CHANGE | DBPROPVAL_UP_INSERT | DBPROPVAL_UP_DELETE;
|
|
i++;
|
|
}
|
|
|
|
if (g_rgDBPrpt[IDX_OtherInsert].fProviderSupported)
|
|
{
|
|
DBProp[i].dwPropertyID= DBPROP_OTHERINSERT;
|
|
DBProp[i].dwOptions=0;
|
|
DBProp[i].vValue.vt=VT_BOOL;
|
|
DBProp[i].colid = DB_NULLID;
|
|
V_BOOL(&(DBProp[i].vValue))=VARIANT_TRUE;
|
|
i++;
|
|
}
|
|
|
|
if (g_rgDBPrpt[IDX_OtherUpdateDelete].fProviderSupported)
|
|
{
|
|
DBProp[i].dwPropertyID= DBPROP_OTHERUPDATEDELETE;
|
|
DBProp[i].dwOptions=0;
|
|
DBProp[i].vValue.vt=VT_BOOL;
|
|
DBProp[i].colid = DB_NULLID;
|
|
V_BOOL(&(DBProp[i].vValue))=VARIANT_TRUE;
|
|
i++;
|
|
}
|
|
|
|
//Build one set of rowset properties
|
|
RowsetPropSet.rgProperties = DBProp;
|
|
RowsetPropSet.cProperties = i;
|
|
RowsetPropSet.guidPropertySet = DBPROPSET_ROWSET;
|
|
|
|
//Now we'll be ready to execute and get a buffered mode rowset
|
|
SetRowsetProperties(&RowsetPropSet, 1);
|
|
|
|
return fInit;
|
|
}
|
|
|
|
|
|
//--------------------------------------------------------------------
|
|
// makes sure props are set.
|
|
// @mfunc
|
|
//--------------------------------------------------------------------
|
|
HRESULT CTxnChgUpdRowset::ReSetProps()
|
|
{
|
|
const ULONG cProps = 3;
|
|
DBPROP DBProp[cProps];
|
|
DBPROPSET RowsetPropSet;
|
|
ULONG i = 0;
|
|
|
|
if (g_rgDBPrpt[IDX_IRowsetChange].fProviderSupported)
|
|
{ //Now reset all properties and include IRowsetUpdate
|
|
DBProp[0].dwPropertyID = DBPROP_IRowsetChange;
|
|
DBProp[0].dwOptions=0;
|
|
DBProp[0].vValue.vt=VT_BOOL;
|
|
DBProp[0].colid = DB_NULLID;
|
|
V_BOOL(&(DBProp[0].vValue))=VARIANT_TRUE;
|
|
|
|
DBProp[1].dwPropertyID= DBPROP_IRowsetUpdate;
|
|
DBProp[1].dwOptions=0;
|
|
DBProp[1].vValue.vt=VT_BOOL;
|
|
DBProp[1].colid = DB_NULLID;
|
|
V_BOOL(&(DBProp[1].vValue))=VARIANT_TRUE;
|
|
|
|
DBProp[2].dwPropertyID= DBPROP_UPDATABILITY;
|
|
DBProp[2].dwOptions=0;
|
|
DBProp[2].vValue.vt=VT_I4;
|
|
DBProp[2].colid = DB_NULLID;
|
|
DBProp[2].vValue.lVal= DBPROPVAL_UP_CHANGE | DBPROPVAL_UP_INSERT | DBPROPVAL_UP_DELETE;
|
|
|
|
//Build one set of rowset properties
|
|
RowsetPropSet.rgProperties = DBProp;
|
|
RowsetPropSet.cProperties = cProps;
|
|
RowsetPropSet.guidPropertySet = DBPROPSET_ROWSET;
|
|
|
|
//Now we'll be ready to execute and get a buffered mode rowset
|
|
return SetRowsetProperties(&RowsetPropSet, 1);
|
|
}
|
|
else
|
|
{
|
|
return S_OK;
|
|
}
|
|
|
|
}
|
|
|
|
|
|
//--------------------------------------------------------------------
|
|
// Does init for buffered mode rowset.
|
|
// @mfunc CreateRowset
|
|
//--------------------------------------------------------------------
|
|
HRESULT CTxnChgUpdRowset::MakeRowset()
|
|
{
|
|
m_hr = NOERROR;
|
|
|
|
//We may already have an update and rowset interface, in which
|
|
//case we are assuming that MakeRowset above did not create a new
|
|
//rowset, and our interfaces will still be valid, so we'll just return
|
|
if (!m_pIRowsetUpdate)
|
|
{
|
|
//Create the rowset and get IRowsetUpdate interface to it
|
|
if (CHECK(m_hr = ReSetProps(), S_OK)) {
|
|
//Create the rowset and get IRowsetUpdate interface to it
|
|
if (CHECK(m_hr = CTxnChgRowset::MakeRowset(), S_OK))
|
|
{
|
|
//If our Init passed, we know IRowsetUpdate should always be available
|
|
if (VerifyInterface(m_pIAccessor, IID_IRowsetUpdate, ROWSET_INTERFACE,
|
|
(IUnknown **)&m_pIRowsetUpdate))
|
|
{
|
|
if (VerifyInterface(m_pIAccessor, IID_IRowset, ROWSET_INTERFACE,
|
|
(IUnknown **)&m_pIRowset))
|
|
{
|
|
return NOERROR;
|
|
}
|
|
else
|
|
{
|
|
m_hr = ResultFromScode(E_NOINTERFACE);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
m_hr = ResultFromScode(E_NOINTERFACE);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return m_hr;
|
|
}
|
|
|
|
//--------------------------------------------------------------------
|
|
// Does init for buffered mode rowset.
|
|
// @mfunc CreateRowset
|
|
//--------------------------------------------------------------------
|
|
HRESULT CTxnChgUpdRowset::FreeRowset()
|
|
{
|
|
SAFE_RELEASE(m_pIRowsetUpdate);
|
|
SAFE_RELEASE(m_pIRowset);
|
|
|
|
ReleaseRowsetObject();
|
|
|
|
return NOERROR;
|
|
}
|
|
|
|
//--------------------------------------------------------------------
|
|
// Verifies pending row from change, if rowset isn't zombied
|
|
// @mfunc CheckPendingRow
|
|
//--------------------------------------------------------------------
|
|
BOOL CTxnChgUpdRowset::CheckPendingRow(ULONG cPendingRows)
|
|
{
|
|
BOOL fResults = FALSE;
|
|
ULONG i;
|
|
ULONG cPending;
|
|
|
|
|
|
if (!cPendingRows)
|
|
{
|
|
cPending=S_FALSE;//no rows are pending
|
|
}
|
|
else
|
|
{
|
|
cPending=S_OK;
|
|
}
|
|
|
|
//We know the rowset should be in tact, so we can check PendingRows
|
|
if (CHECK(m_pIRowsetUpdate->GetPendingRows( NULL,
|
|
DBPENDINGSTATUS_NEW | DBPENDINGSTATUS_CHANGED | DBPENDINGSTATUS_DELETED,
|
|
&m_cPendingRows,
|
|
&m_rgPendingRows,
|
|
&m_rgPendingStatus), cPending))
|
|
{
|
|
//THESE ARE COMMENTED OUT BECAUSE THESE >CAN< BE NULL & ZERO IF NO ROWS ARE PENDING
|
|
//Make sure our pointers are valid
|
|
//if (!m_rgPendingRows || !m_rgPendingStatus)
|
|
// goto CLEANUP;
|
|
|
|
//Make sure we have the right number of pending changes
|
|
if (COMPARE(m_cPendingRows, cPendingRows))
|
|
{
|
|
//For each row, check the status
|
|
for (i=0; i<cPendingRows; i++)
|
|
{
|
|
COMPARE(m_rgPendingStatus[i], DBPENDINGSTATUS_CHANGED);
|
|
}
|
|
|
|
fResults = TRUE;
|
|
}
|
|
}
|
|
//CLEANUP:
|
|
//Release the row
|
|
if (m_rgPendingRows)
|
|
CHECK(m_pIRowset->ReleaseRows(m_cPendingRows, m_rgPendingRows,
|
|
NULL, NULL, NULL), S_OK);
|
|
|
|
if (m_rgPendingStatus)
|
|
m_pIMalloc->Free(m_rgPendingStatus);
|
|
return fResults;
|
|
}
|
|
|
|
//--------------------------------------------------------------------
|
|
// Does all termination, including releasing m_pIRowsetUpdate if needed.
|
|
// @mfunc Terminate
|
|
//--------------------------------------------------------------------
|
|
BOOL CTxnChgUpdRowset::Terminate()
|
|
{
|
|
SAFE_RELEASE(m_pIRowsetUpdate);
|
|
SAFE_RELEASE(m_pIRowset);
|
|
|
|
return CTxnChgRowset::Terminate();
|
|
}
|
|
|
|
|
|
//--------------------------------------------------------------------
|
|
// Inits the CTxnUpdate Object. It inits the encapsulated objects
|
|
// which are unique to CTxnUpdate
|
|
// @mfunc Init
|
|
//--------------------------------------------------------------------
|
|
BOOL CTxnUpdate::Init()
|
|
{
|
|
if (CTxn::Init())
|
|
{
|
|
//Create our encapsulated ChgUpdRowset objects
|
|
m_pChgUpdRowset1 = new CTxnChgUpdRowset((LPWSTR)gwszModuleName);
|
|
m_pChgUpdRowset2 = new CTxnChgUpdRowset((LPWSTR)gwszModuleName);
|
|
|
|
if (m_pChgUpdRowset1 && m_pChgUpdRowset2)
|
|
{
|
|
//Initialize pointers
|
|
m_pChgUpdRowset1->m_pIRowsetUpdate = NULL;
|
|
m_pChgUpdRowset1->m_pIRowset = NULL;
|
|
m_pChgUpdRowset1->m_cPendingRows = 0;
|
|
m_pChgUpdRowset1->m_rgPendingRows = NULL;
|
|
m_pChgUpdRowset1->m_rgPendingStatus = NULL;
|
|
|
|
m_pChgUpdRowset2->m_pIRowsetUpdate = NULL;
|
|
m_pChgUpdRowset2->m_pIRowset = NULL;
|
|
m_pChgUpdRowset2->m_cPendingRows = 0;
|
|
m_pChgUpdRowset2->m_rgPendingRows = NULL;
|
|
m_pChgUpdRowset2->m_rgPendingStatus = NULL;
|
|
|
|
//Copy the stuff which normally gets initialized at
|
|
//testcase initialization time, but didn't for these
|
|
//objects since they are encapsulated rather than
|
|
//inherited by the testcase object.
|
|
CopyTestCaseInfo(m_pChgUpdRowset1);
|
|
CopyTestCaseInfo(m_pChgUpdRowset2);
|
|
|
|
//Set the same DSO and table for our encapsulated rowset objects
|
|
//also create each rowset
|
|
if (m_pChgUpdRowset1->Init() &&
|
|
m_pChgUpdRowset2->Init())
|
|
return TRUE;
|
|
}
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
//--------------------------------------------------------------------
|
|
// Releases all rowsets associated with encapsulated rowset objects
|
|
// and does an abort of all open transactions
|
|
// @mfunc ReleaseAllRowsetsAndTxns
|
|
//--------------------------------------------------------------------
|
|
void CTxnUpdate::ReleaseAllRowsetsAndTxns()
|
|
{
|
|
//Clean up all rowset interfaces
|
|
m_pChgUpdRowset1->ReleaseRowsetObject();
|
|
SAFE_RELEASE(m_pChgUpdRowset1->m_pIRowset);
|
|
SAFE_RELEASE(m_pChgUpdRowset1->m_pIRowsetUpdate);
|
|
|
|
m_pChgUpdRowset2->ReleaseRowsetObject();
|
|
SAFE_RELEASE(m_pChgUpdRowset2->m_pIRowset);
|
|
SAFE_RELEASE(m_pChgUpdRowset2->m_pIRowsetUpdate);
|
|
|
|
//We don't have a return value, since its just cleanup,
|
|
//which may not succeed because its not necessary
|
|
m_pChgUpdRowset1->Abort(FALSE, FALSE);
|
|
m_pChgUpdRowset2->Abort(FALSE, FALSE);
|
|
}
|
|
|
|
|
|
//--------------------------------------------------------------------
|
|
// Cleans up the CTxn Object
|
|
// @mfunc Terminate
|
|
//--------------------------------------------------------------------
|
|
BOOL CTxnUpdate::Terminate()
|
|
{
|
|
//Clean up encapsulated objects
|
|
if (m_pChgUpdRowset1)
|
|
{
|
|
m_pChgUpdRowset1->Terminate();
|
|
delete m_pChgUpdRowset1;
|
|
}
|
|
|
|
if (m_pChgUpdRowset2)
|
|
{
|
|
m_pChgUpdRowset2->Terminate();
|
|
delete m_pChgUpdRowset2;
|
|
}
|
|
|
|
return CTxn::Terminate();
|
|
}
|
|
|
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Miscellaneous Function Definitions
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
|
|
|
|
//--------------------------------------------------------------------
|
|
// Does a non retaining commit on the given rowset. This function is
|
|
// intended to be envoked by CreateThread or ResumeThread, so the commit
|
|
// will be done on a second thread.
|
|
//
|
|
// @mfunc ThreadCommit
|
|
//--------------------------------------------------------------------
|
|
LRESULT ThreadCommit(LPVOID pChgRowset)
|
|
{
|
|
ULONG ul = 0;
|
|
|
|
//We want to make sure our other operation has a chance to start before we continue.
|
|
//Specifying zero will immediately turn our time slice over to another thread.
|
|
Sleep(0);
|
|
|
|
if (FAILED(CoInitialize(NULL)))
|
|
return ResultFromScode(E_FAIL);
|
|
|
|
ul = (ULONG)((CTxnChgRowset *)pChgRowset)->m_pITxnLocal->Commit(FALSE, 0, 0);
|
|
CoUninitialize();
|
|
|
|
return ul;
|
|
}
|
|
|
|
//--------------------------------------------------------------------
|
|
// Does a non retaining abort on the given rowset. This function is
|
|
// intended to be envoked by CreateThread or ResumeThread, so the abort
|
|
// will be done on a second thread.
|
|
//
|
|
// @mfunc ThreadAbort
|
|
//--------------------------------------------------------------------
|
|
LRESULT ThreadAbort(LPVOID pChgRowset)
|
|
{
|
|
ULONG ul = 0;
|
|
|
|
//We want to make sure our other operation has a chance to start before we continue.
|
|
//Specifying zero will immediately turn our time slice over to another thread.
|
|
Sleep(0);
|
|
|
|
if (FAILED(CoInitialize(NULL)))
|
|
return ResultFromScode(E_FAIL);
|
|
|
|
ul = (ULONG)((CTxnChgRowset *)pChgRowset)->m_pITxnLocal->Abort(NULL, FALSE, FALSE);
|
|
CoUninitialize();
|
|
|
|
return ul;
|
|
}
|
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Test Case Section
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
|
|
// {{ TCW_TEST_CASE_MAP(TCIsoLevel)
|
|
//--------------------------------------------------------------------
|
|
// @class Isolation Level Testing
|
|
//
|
|
class TCIsoLevel : public CTxnImmed {
|
|
private:
|
|
// @cmember Static array of variations
|
|
DECLARE_TEST_CASE_DATA();
|
|
public:
|
|
// {{ TCW_DECLARE_FUNCS
|
|
// @cmember Execution Routine
|
|
DECLARE_TEST_CASE_FUNCS(TCIsoLevel,CTxnImmed);
|
|
// }}
|
|
|
|
// @cmember Initialization Routine
|
|
virtual BOOL Init();
|
|
// @cmember Termination Routine
|
|
virtual BOOL Terminate();
|
|
|
|
// {{ TCW_TESTVARS()
|
|
// @cmember Positive ISOLEVEL
|
|
int Variation_1();
|
|
// @cmember Chaos
|
|
int Variation_2();
|
|
// }}
|
|
};
|
|
// {{ TCW_TESTCASE(TCIsoLevel)
|
|
#define THE_CLASS TCIsoLevel
|
|
BEG_TEST_CASE(TCIsoLevel, CTxnImmed, L"Isolation Level Testing")
|
|
TEST_VARIATION(1, L"Positive ISOLEVEL")
|
|
TEST_VARIATION(2, L"Chaos")
|
|
END_TEST_CASE()
|
|
#undef THE_CLASS
|
|
// }}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_TEST_CASE_MAP(TCEnListmentNULL)
|
|
//--------------------------------------------------------------------
|
|
// @class Enlistment Testing
|
|
//
|
|
class TCEnListmentNULL : public CTxnImmed {
|
|
private:
|
|
// @cmember Static array of variations
|
|
DECLARE_TEST_CASE_DATA();
|
|
public:
|
|
// {{ TCW_DECLARE_FUNCS
|
|
// @cmember Execution Routine
|
|
DECLARE_TEST_CASE_FUNCS(TCEnListmentNULL,CTxnImmed);
|
|
// }}
|
|
|
|
// @cmember Initialization Routine
|
|
virtual BOOL Init();
|
|
// @cmember Termination Routine
|
|
virtual BOOL Terminate();
|
|
|
|
// {{ TCW_TESTVARS()
|
|
// @cmember Join-Commit-UnEnlist-reEnlist
|
|
int Variation_1();
|
|
// @cmember Join-Abort-UnEnlist-reEnlist
|
|
int Variation_2();
|
|
// @cmember Back to back UnEnlists, no pending work
|
|
int Variation_3();
|
|
// @cmember UnEnList but not enlisted
|
|
int Variation_4();
|
|
// @cmember Join Committed session with new MTSTxn
|
|
int Variation_5();
|
|
// @cmember Join Aborted session with new MTSTxn
|
|
int Variation_6();
|
|
// @cmember UnEnlists, pending work
|
|
int Variation_7();
|
|
// }}
|
|
};
|
|
// {{ TCW_TESTCASE(EnListment)
|
|
#define THE_CLASS TCEnListmentNULL
|
|
BEG_TEST_CASE(TCEnListmentNULL, CTxnImmed, L"Enlistment Testing")
|
|
TEST_VARIATION(1, L"Join-Commit-UnEnlist-reEnlist")
|
|
TEST_VARIATION(2, L"Join-Abort-UnEnlist-reEnlist")
|
|
TEST_VARIATION(3, L"Back to back UnEnlists, no pending work")
|
|
TEST_VARIATION(4, L"UnEnList but no txn")
|
|
TEST_VARIATION(5, L"Join Committed session with new MTSTxn")
|
|
TEST_VARIATION(6, L"Join Aborted session with new MTSTxn")
|
|
TEST_VARIATION(7, L"UnEnlists, pending work")
|
|
END_TEST_CASE()
|
|
#undef THE_CLASS
|
|
// }}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_TEST_CASE_MAP(TCEnListment)
|
|
//--------------------------------------------------------------------
|
|
// @class Enlistment Testing
|
|
//
|
|
class TCEnListment : public CTxnImmed {
|
|
private:
|
|
// @cmember Static array of variations
|
|
DECLARE_TEST_CASE_DATA();
|
|
public:
|
|
// {{ TCW_DECLARE_FUNCS
|
|
// @cmember Execution Routine
|
|
DECLARE_TEST_CASE_FUNCS(TCEnListment,CTxnImmed);
|
|
// }}
|
|
|
|
// @cmember Initialization Routine
|
|
virtual BOOL Init();
|
|
// @cmember Termination Routine
|
|
virtual BOOL Terminate();
|
|
|
|
// {{ TCW_TESTVARS()
|
|
// @cmember Join-Commit-reEnlist
|
|
int Variation_1();
|
|
// @cmember Join-Abort-reEnlist
|
|
int Variation_2();
|
|
// @cmember Back to back Enlists
|
|
int Variation_3();
|
|
// @cmember Test MTS after Commit
|
|
int Variation_4();
|
|
// @cmember Test MTS after Abort
|
|
int Variation_5();
|
|
// @cmember Back to back Enlists - different txns
|
|
int Variation_6();
|
|
// @cmember Join-Commit-unEnlist-reEnlist
|
|
int Variation_7();
|
|
// @cmember Join before firehose mode
|
|
int Variation_8();
|
|
// @cmember Join after firehose mode
|
|
int Variation_9();
|
|
// @cmember commit with 2 commands open
|
|
int Variation_10();
|
|
// @cmember DBPROP_RESETDATASOURCE
|
|
int Variation_11();
|
|
// }}
|
|
};
|
|
// {{ TCW_TESTCASE(EnListment)
|
|
#define THE_CLASS TCEnListment
|
|
BEG_TEST_CASE(TCEnListment, CTxnImmed, L"Enlistment Testing")
|
|
TEST_VARIATION(1, L"Join-Commit-reEnlist")
|
|
TEST_VARIATION(2, L"Join-Abort-reEnlist")
|
|
TEST_VARIATION(3, L"Back to back Enlists")
|
|
TEST_VARIATION(4, L"Test MTS after Commit")
|
|
TEST_VARIATION(5, L"Test MTS after Abort")
|
|
TEST_VARIATION(6, L"Back to back Enlists - different txns")
|
|
TEST_VARIATION(7, L"Join-Commit-unEnlist-reEnlist")
|
|
TEST_VARIATION(8, L"Join before firehose mode")
|
|
TEST_VARIATION(9, L"Join after firehose mode")
|
|
TEST_VARIATION(10, L"commit with 2 commands open")
|
|
TEST_VARIATION(11, L"DBPROP_RESETDATASOURCE")
|
|
END_TEST_CASE()
|
|
#undef THE_CLASS
|
|
// }}
|
|
// }}
|
|
|
|
// {{ TCW_TEST_CASE_MAP(TCRetainPreserve)
|
|
//--------------------------------------------------------------------
|
|
// @class Retaining/Preserving Behavior
|
|
//
|
|
class TCRetainPreserve : public CTxnImmed {
|
|
private:
|
|
// @cmember Static array of variations
|
|
DECLARE_TEST_CASE_DATA();
|
|
|
|
public:
|
|
// {{ TCW_DECLARE_FUNCS
|
|
// @cmember Execution Routine
|
|
DECLARE_TEST_CASE_FUNCS(TCRetainPreserve,CTxnImmed);
|
|
// }}
|
|
|
|
// @cmember Initialization Routine
|
|
virtual BOOL Init();
|
|
// @cmember Termination Routine
|
|
virtual BOOL Terminate();
|
|
//@cmember Function to test Commit with fRetaining = TRUE
|
|
BOOL CommitRetain(ISOLEVEL fIsoLevel);
|
|
//@cmember Function to test Commit with fRetaining = FALSE
|
|
BOOL CommitNonRetain(ISOLEVEL fIsoLevel);
|
|
//@cmember Function to test Abort with fRetaining = TRUE
|
|
BOOL AbortRetain(ISOLEVEL fIsoLevel);
|
|
//@cmember Function to test Abort with fRetaining = FALSE
|
|
BOOL AbortNonRetain(ISOLEVEL fIsoLevel);
|
|
|
|
// {{ TCW_TESTVARS()
|
|
// @cmember Commit(fRetaining = TRUE
|
|
int Variation_1();
|
|
// @cmember Commit(fRetaining = FALSE
|
|
int Variation_2();
|
|
// @cmember Abort(fRetaining = TRUE
|
|
int Variation_3();
|
|
// @cmember Abort(fRetaining = FALSE
|
|
int Variation_4();
|
|
// }}
|
|
};
|
|
// {{ TCW_TESTCASE(TCRetainPreserve)
|
|
#define THE_CLASS TCRetainPreserve
|
|
BEG_TEST_CASE(TCRetainPreserve, CTxnImmed, L"Retaining/Preserving Behavior")
|
|
TEST_VARIATION(1, L"Commit(fRetaining = TRUE")
|
|
TEST_VARIATION(2, L"Commit(fRetaining = FALSE")
|
|
TEST_VARIATION(3, L"Abort(fRetaining = TRUE")
|
|
TEST_VARIATION(4, L"Abort(fRetaining = FALSE")
|
|
END_TEST_CASE()
|
|
#undef THE_CLASS
|
|
// }}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_TEST_CASE_MAP(TCIRowsetUpdate)
|
|
//--------------------------------------------------------------------
|
|
// @class Transacted rowsets in Buffered Update mode
|
|
//
|
|
class TCIRowsetUpdate : public CTxnUpdate {
|
|
private:
|
|
// @cmember Static array of variations
|
|
DECLARE_TEST_CASE_DATA();
|
|
|
|
public:
|
|
// {{ TCW_DECLARE_FUNCS
|
|
// @cmember Execution Routine
|
|
DECLARE_TEST_CASE_FUNCS(TCIRowsetUpdate,CTxnUpdate);
|
|
// }}
|
|
|
|
// @cmember Initialization Routine
|
|
virtual BOOL Init();
|
|
// @cmember Termination Routine
|
|
virtual BOOL Terminate();
|
|
|
|
// {{ TCW_TESTVARS()
|
|
// @cmember Change, Abort with fRetaining = FALSE, Update
|
|
int Variation_1();
|
|
// @cmember Change, Update, Abort with fRetaining = FALSE
|
|
int Variation_2();
|
|
// @cmember Change, Commit with fRetaining = FALSE, Update
|
|
int Variation_3();
|
|
// @cmember Change, Update, Commit with fRetaining = FALSE
|
|
int Variation_4();
|
|
// @cmember Open read only rowset
|
|
int Variation_5();
|
|
// @cmember Change, Join Txn, Update, Abort with fRetaining = FALSE
|
|
int Variation_6();
|
|
// @cmember Change, Update, Join Txn, Abort with fRetaining = FALSE
|
|
int Variation_7();
|
|
// @cmember Change, Join Txn, Update, Commit with fRetaining = FALSE
|
|
int Variation_8();
|
|
// @cmember Change, Update, Join Txn, Commit with fRetaining = FALSE
|
|
int Variation_9();
|
|
// }}
|
|
};
|
|
// {{ TCW_TESTCASE(TCIRowsetUpdate)
|
|
#define THE_CLASS TCIRowsetUpdate
|
|
BEG_TEST_CASE(TCIRowsetUpdate, CTxnUpdate, L"Transacted rowsets in Buffered Update mode")
|
|
TEST_VARIATION(1, L"Change, Abort with fRetaining = FALSE, Update")
|
|
TEST_VARIATION(2, L"Change, Update, Abort with fRetaining = FALSE")
|
|
TEST_VARIATION(3, L"Change, Commit with fRetaining = FALSE, Update")
|
|
TEST_VARIATION(4, L"Change, Update, Commit with fRetaining = FALSE")
|
|
TEST_VARIATION(5, L"Open read only rowset")
|
|
TEST_VARIATION(6, L"Change, Join Txn, Update, Abort with fRetaining = FALSE")
|
|
TEST_VARIATION(7, L"Change, Update, Join Txn, Abort with fRetaining = FALSE")
|
|
TEST_VARIATION(8, L"Change, Join Txn, Update, Commit with fRetaining = FALSE")
|
|
TEST_VARIATION(9, L"Change, Update, Join Txn, Commit with fRetaining = FALSE")
|
|
END_TEST_CASE()
|
|
#undef THE_CLASS
|
|
// }}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_TEST_CASE_MAP(CNoTxn)
|
|
//--------------------------------------------------------------------
|
|
// @class Abort and Commit called before StartTransaction
|
|
//
|
|
class CNoTxn : public CTxnImmed {
|
|
private:
|
|
// @cmember Static array of variations
|
|
DECLARE_TEST_CASE_DATA();
|
|
//ITransactionLocal interface
|
|
|
|
public:
|
|
// {{ TCW_DECLARE_FUNCS
|
|
// @cmember Execution Routine
|
|
DECLARE_TEST_CASE_FUNCS(CNoTxn,CTxnImmed);
|
|
// }}
|
|
|
|
// @cmember Initialization Routine
|
|
virtual BOOL Init();
|
|
// @cmember Termination Routine
|
|
virtual BOOL Terminate();
|
|
|
|
// {{ TCW_TESTVARS()
|
|
// @cmember Abort with fRetaining = FALSE before coordinated txn is joined
|
|
int Variation_1();
|
|
// @cmember Commit with fRetaining = FALSE before StartTransaction - XACT_E_NOTRANSACTION
|
|
int Variation_2();
|
|
// @cmember GetTransactionInfo before StartTransaction - XACT_E_NOTRANSACTION
|
|
int Variation_3();
|
|
// @cmember GetOptionsObject before StartTransaction - S_OK
|
|
int Variation_4();
|
|
// @cmember Abort with fRetaining = TRUE before StartTransaction - XACT_E_NOTRANSACTION
|
|
int Variation_5();
|
|
// }}
|
|
};
|
|
// {{ TCW_TESTCASE(CNoTxn)
|
|
#define THE_CLASS CNoTxn
|
|
BEG_TEST_CASE(CNoTxn, CSessionObject, L"Abort and Commit after local changes")
|
|
TEST_VARIATION(1, L"Start a coordinated txn, make a change, abort it, look for change")
|
|
TEST_VARIATION(2, L"Make a change, start a coordinated txn, join it, abort it, look for change")
|
|
TEST_VARIATION(3, L"Make a change, start a coordinated txn, join it, commit it, look for change")
|
|
TEST_VARIATION(4, L"GetOptionsObject before StartTransaction - S_OK")
|
|
TEST_VARIATION(5, L"Start a coordinated txn, make a change, join the coord txn, abort it, look for change")
|
|
END_TEST_CASE()
|
|
#undef THE_CLASS
|
|
// }}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_TEST_CASE_MAP(CMultipleTxns)
|
|
//--------------------------------------------------------------------
|
|
// @class Multiple Transactions
|
|
//
|
|
class CMultipleTxns : public CTxnImmed {
|
|
private:
|
|
// @cmember Static array of variations
|
|
DECLARE_TEST_CASE_DATA();
|
|
|
|
public:
|
|
// {{ TCW_DECLARE_FUNCS
|
|
// @cmember Execution Routine
|
|
DECLARE_TEST_CASE_FUNCS(CMultipleTxns,CTxnImmed);
|
|
// }}
|
|
|
|
//@cmember Second table for second rowset
|
|
CTable * m_pTable;
|
|
//@cemember Actual delete count for second table
|
|
ULONG m_ulCurrentDelete;
|
|
//@cemember Actual insert count for second table
|
|
ULONG m_ulCurrentInsert;
|
|
|
|
// @cmember Initialization Routine
|
|
virtual BOOL Init();
|
|
// @cmember Termination Routine
|
|
virtual BOOL Terminate();
|
|
|
|
// {{ TCW_TESTVARS()
|
|
// @cmember Abort two transactions on same DSO
|
|
int Variation_1();
|
|
// @cmember Commit two transactions on same DSO
|
|
int Variation_2();
|
|
// @cmember Abort one transaction, commit the other, on same DSO
|
|
int Variation_3();
|
|
// @cmember Abort and Commit with multiple commands/rowsets active
|
|
int Variation_4();
|
|
// @cmember Multiple Sessions, Transaction on only one
|
|
int Variation_5();
|
|
// @cmember Abort and Commit from 2 session, each to it's own coord txn
|
|
int Variation_6();
|
|
// @cmember Two sessions, UnEnlist from one
|
|
int Variation_7();
|
|
// }}
|
|
};
|
|
// {{ TCW_TESTCASE(CMultipleTxns)
|
|
#define THE_CLASS CMultipleTxns
|
|
BEG_TEST_CASE(CMultipleTxns, CTxnImmed, L"Multiple Transactions")
|
|
TEST_VARIATION(1, L"Abort two transactions on same DSO")
|
|
TEST_VARIATION(2, L"Commit two transactions on same DSO")
|
|
TEST_VARIATION(3, L"Abort one transaction, commit the other, on same DSO")
|
|
TEST_VARIATION(4, L"Abort and Commit with multiple commands/rowsets active")
|
|
TEST_VARIATION(5, L"Multiple Sessions, Transaction on only one")
|
|
TEST_VARIATION(6, L"Abort and Commit from 2 session, each to it's own coord txn")
|
|
TEST_VARIATION(7, L"Two sessions, UnEnlist from one")
|
|
END_TEST_CASE()
|
|
#undef THE_CLASS
|
|
// }}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_TEST_CASE_MAP(CSequence)
|
|
//--------------------------------------------------------------------
|
|
// @class Sequence testing for StartTransaction and ITransactionOptions
|
|
//
|
|
class CSequence : public CTxn {
|
|
private:
|
|
// @cmember Static array of variations
|
|
DECLARE_TEST_CASE_DATA();
|
|
|
|
public:
|
|
// {{ TCW_DECLARE_FUNCS
|
|
// @cmember Execution Routine
|
|
DECLARE_TEST_CASE_FUNCS(CSequence,CTxn);
|
|
// }}
|
|
|
|
//@cmember Coordinated Transaction interface
|
|
ITransaction *m_pITransaction;
|
|
//@cmember Joined Transaction interface
|
|
ITransactionJoin *m_pITxnJoin;
|
|
//@cmember Transaction Options interface
|
|
ITransactionOptions *m_pITxnOptions;
|
|
//@cmember Options struct
|
|
XACTOPT m_TxnOptions;
|
|
|
|
// @cmember Initialization Routine
|
|
virtual BOOL Init();
|
|
// @cmember Termination Routine
|
|
virtual BOOL Terminate();
|
|
//@cmember Start DTC, coordinated transaction
|
|
BOOL StartCoordTxn( ITransaction **ppITransaction,ISOLEVEL isolevel);
|
|
//@cmember gwt txnjoin object
|
|
HRESULT GetTxnJoin(); // @parm [OUT] Session Pointer)
|
|
//@cmember free txn join session object
|
|
BOOL FreeJoinTxn() ;
|
|
//@cmember free DTC, coordinated transaction
|
|
BOOL FreeCoordTxn(ITransaction *pITransaction);
|
|
//@cmember Cleanup function for this derived class
|
|
virtual void ReleaseAllRowsetsAndTxns()
|
|
{
|
|
//Cleanup our transaction, if we have one
|
|
if (m_pITransaction)
|
|
{
|
|
m_pITransaction->Commit(FALSE, 0, 0);
|
|
}
|
|
}
|
|
|
|
// {{ TCW_TESTVARS()
|
|
// @cmember GetOptionsObject before StartTransaction
|
|
int Variation_1();
|
|
// @cmember GetOptionsObject after StartTransaction
|
|
int Variation_2();
|
|
// @cmember SetOptions twice
|
|
int Variation_3();
|
|
// }}
|
|
};
|
|
// {{ TCW_TESTCASE(CSequence)
|
|
#define THE_CLASS CSequence
|
|
BEG_TEST_CASE(CSequence, CTxn, L"Sequence testing for StartTransaction and ITransactionOptions")
|
|
TEST_VARIATION(1, L"GetOptionsObject before StartTransaction")
|
|
TEST_VARIATION(2, L"GetOptionsObject after StartTransaction")
|
|
TEST_VARIATION(3, L"SetOptions twice")
|
|
END_TEST_CASE()
|
|
#undef THE_CLASS
|
|
// }}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_TEST_CASE_MAP(TCExtendedErrors)
|
|
//--------------------------------------------------------------------
|
|
// @class Extended Errors
|
|
//
|
|
class TCExtendedErrors : public CTxnImmed {
|
|
private:
|
|
// @cmember Static array of variations
|
|
DECLARE_TEST_CASE_DATA();
|
|
|
|
// @cmember Txn Object interface for session
|
|
ITransactionOptions * m_pITxnOptions;
|
|
|
|
public:
|
|
// {{ TCW_DECLARE_FUNCS
|
|
// @cmember Execution Routine
|
|
DECLARE_TEST_CASE_FUNCS(TCExtendedErrors,CTxnImmed);
|
|
// }}
|
|
|
|
|
|
// @cmember Initialization Routine
|
|
virtual BOOL Init();
|
|
// @cmember Termination Routine
|
|
virtual BOOL Terminate();
|
|
|
|
// {{ TCW_TESTVARS()
|
|
// @cmember Valid ITransactionLocal calls with previous error object existing.
|
|
int Variation_1();
|
|
// @cmember Valid Abort call with previous error object existing.
|
|
int Variation_2();
|
|
// @cmember Valid SetOptions call with previous error object existing.
|
|
int Variation_3();
|
|
// @cmember Valid GetOptions call with previous error object existing.
|
|
int Variation_4();
|
|
// @cmember XACT_E_NOTSUPPORTED Commit call with previous error object existing
|
|
int Variation_5();
|
|
// @cmember XACT_E_NOISORETAIN JoinTransaction call with previous error object existing
|
|
int Variation_6();
|
|
// @cmember E_INVALIDARG GetTransactionInfo call with previous error object existing
|
|
int Variation_7();
|
|
// @cmember E_INVALIDARG GetOptions call with previous error object existing
|
|
int Variation_8();
|
|
// @cmember E_INVALIDARG SetOptions call with previous error object existing
|
|
int Variation_9();
|
|
// @cmember XACT_E_ISOLATIONLEVEL NULL & INVALID ISOLEVEL
|
|
int Variation_10();
|
|
// @cmember E_INVALIDARG GetOptionObject calls no with previous error object existing
|
|
int Variation_11();
|
|
// @cmember E_INVALIDARG SetOptions calls with no previous error object existing
|
|
int Variation_12();
|
|
// @cmember E_INVALIDARG GetOptions calls with no previous error object existing
|
|
int Variation_13();
|
|
// @cmember Valid Abort calls with previous error object existing, check error on ITransaction
|
|
int Variation_14();
|
|
// @cmember Valid TransactionLocal calls with previous error object existing, check error on ITransaction
|
|
int Variation_15();
|
|
// @cmember punkTransactionCoord NULL isoflag ignored
|
|
int Variation_16();
|
|
// @cmember punkTransactionCoord NULL isoflag ignored
|
|
int Variation_17();
|
|
// @cmember punkTransactionCoord NULL isolevel ignored
|
|
int Variation_18();
|
|
// @cmember punkTransactionCoord NULL isolevel ignored
|
|
int Variation_19();
|
|
// @cmember XACT_E_ISOLATIONLEVEL INVALID ISOLEVEL
|
|
int Variation_20();
|
|
// @cemeber Start/Join/XACT_E_XTIONEXISTS
|
|
int Variation_21();
|
|
// }}
|
|
};
|
|
// {{ TCW_TESTCASE(TCExtendedErrors)
|
|
#define THE_CLASS TCExtendedErrors
|
|
BEG_TEST_CASE(TCExtendedErrors, CTxnImmed, L"Extended Errors")
|
|
TEST_VARIATION(1, L"Valid ITransactionLocal calls with previous error object existing.")
|
|
TEST_VARIATION(2, L"Valid Abort call with previous error object existing.")
|
|
TEST_VARIATION(3, L"Valid SetOptions call with previous error object existing.")
|
|
TEST_VARIATION(4, L"Valid GetOptions call with previous error object existing.")
|
|
TEST_VARIATION(5, L"XACT_E_NOTSUPPORTED Commit call with previous error object existing")
|
|
TEST_VARIATION(6, L"XACT_E_NOISORETAIN JoinTransaction call with previous error object existing")
|
|
TEST_VARIATION(7, L"E_INVALIDARG GetTransactionInfo call with previous error object existing")
|
|
TEST_VARIATION(8, L"E_INVALIDARG GetOptions call with previous error object existing")
|
|
TEST_VARIATION(9, L"E_INVALIDARG SetOptions call with previous error object existing")
|
|
TEST_VARIATION(10, L"XACT_E_ISOLATIONLEVEL NULL & INVALID ISOLEVEL")
|
|
TEST_VARIATION(11, L"E_INVALIDARG GetOptionObject calls no with previous error object existing")
|
|
TEST_VARIATION(12, L"E_INVALIDARG SetOptions calls with no previous error object existing")
|
|
TEST_VARIATION(13, L"E_INVALIDARG GetOptions calls with no previous error object existing")
|
|
TEST_VARIATION(14, L"Valid Abort calls with previous error object existing, check error on ITransaction")
|
|
TEST_VARIATION(15, L"Valid TransactionLocal calls with previous error object existing, check error on ITransaction")
|
|
TEST_VARIATION(16, L"punkTransactionCoord NULL isoflag ignored")
|
|
TEST_VARIATION(17, L"punkTransactionCoord NULL isoflag ignored")
|
|
TEST_VARIATION(18, L"punkTransactionCoord NULL isolevel ignored")
|
|
TEST_VARIATION(19, L"punkTransactionCoord NULL isolevel ignored")
|
|
TEST_VARIATION(20, L"XACT_E_ISOLATIONLEVEL INVALID ISOLEVEL")
|
|
TEST_VARIATION(21, L"Start/Join/XACT_E_XTIONEXISTS")
|
|
END_TEST_CASE()
|
|
#undef THE_CLASS
|
|
// }}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_TEST_CASE_MAP(TCRetainPreserve)
|
|
//--------------------------------------------------------------------
|
|
// @class Retaining/Preserving Behavior
|
|
//
|
|
class TCNestedTransactions : public CTxnImmed {
|
|
private:
|
|
// @cmember Static array of variations
|
|
DECLARE_TEST_CASE_DATA();
|
|
|
|
public:
|
|
// {{ TCW_DECLARE_FUNCS
|
|
// @cmember Execution Routine
|
|
DECLARE_TEST_CASE_FUNCS(TCNestedTransactions,CTxnImmed);
|
|
// }}
|
|
|
|
// @cmember Initialization Routine
|
|
virtual BOOL Init();
|
|
// @cmember Termination Routine
|
|
virtual BOOL Terminate();
|
|
|
|
// {{ TCW_TESTVARS()
|
|
// @Legal - Nested Transaction Supported?
|
|
int Variation_1();
|
|
// @Illegal Nested Transaction - 2 ITransactionJoins
|
|
int Variation_2();
|
|
// @Illegal Nested Transaction - Local before Join
|
|
int Variation_3();
|
|
|
|
// }}
|
|
};
|
|
|
|
// {{ TCW_TESTCASE(TCRetainPreserve)
|
|
#define THE_CLASS TCNestedTransactions
|
|
BEG_TEST_CASE(TCNestedTransactions, CTxnImmed, L"Nested Transactions")
|
|
TEST_VARIATION(1, L"Legal - Nested Transaction Supported?")
|
|
TEST_VARIATION(2, L"Illegal Nested Transaction - 2 ITransactionJoins")
|
|
TEST_VARIATION(3, L"Illegal Nested Transaction - Local before Join")
|
|
END_TEST_CASE()
|
|
#undef THE_CLASS
|
|
// }}
|
|
// }}
|
|
|
|
|
|
// }} END_DECLARE_TEST_CASES()
|
|
|
|
// {{ TCW_TESTMODULE(ThisModule)
|
|
TEST_MODULE(10, ThisModule, gwszModuleDescrip)
|
|
TEST_CASE(1, TCIsoLevel)
|
|
TEST_CASE(2, TCEnListmentNULL)
|
|
TEST_CASE(3, TCRetainPreserve)
|
|
TEST_CASE(4, TCIRowsetUpdate)
|
|
TEST_CASE(5, CNoTxn)
|
|
TEST_CASE(6, CMultipleTxns)
|
|
TEST_CASE(7, CSequence)
|
|
TEST_CASE(8, TCExtendedErrors)
|
|
TEST_CASE(9, TCNestedTransactions)
|
|
TEST_CASE(10, TCEnListment)
|
|
END_TEST_MODULE()
|
|
// }}
|
|
|
|
|
|
// {{ TCW_TC_PROTOTYPE(TCIsoLevel)
|
|
//*-----------------------------------------------------------------------
|
|
//| Test Case: TCIsoLevel - Isolation Level Testing
|
|
//| Created: 04/16/96
|
|
//*-----------------------------------------------------------------------
|
|
|
|
//--------------------------------------------------------------------
|
|
// @mfunc TestCase Initialization Routine
|
|
//
|
|
// @rdesc TRUE or FALSE
|
|
//
|
|
BOOL TCIsoLevel::Init()
|
|
{
|
|
// {{ TCW_INIT_BASECLASS_CHECK
|
|
if(CTxnImmed::Init())
|
|
// }}
|
|
{
|
|
//the jet engine (access) does not support distributed transactions
|
|
if (m_fOnAccess)
|
|
{
|
|
return TEST_SKIPPED;
|
|
}
|
|
else
|
|
{
|
|
return TEST_PASS;
|
|
}
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(1)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc Positive ISOLEVEL
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCIsoLevel::Variation_1()
|
|
{
|
|
BOOL fResults = FALSE;
|
|
XACTUOW uow1;
|
|
XACTUOW uow2;
|
|
ITransaction *pITransaction = NULL;
|
|
const ULONG ulIsoNum = 9;
|
|
ISOLATIONLEVEL rgIsoLevel[ulIsoNum];
|
|
ULONG ulIndex = 0;
|
|
ISOLATIONLEVEL IsoLevel;
|
|
|
|
|
|
rgIsoLevel[0] = ISOLATIONLEVEL_CHAOS;
|
|
rgIsoLevel[1] = ISOLATIONLEVEL_READUNCOMMITTED;
|
|
rgIsoLevel[2] = ISOLATIONLEVEL_BROWSE;
|
|
rgIsoLevel[3] = ISOLATIONLEVEL_CURSORSTABILITY;
|
|
rgIsoLevel[4] = ISOLATIONLEVEL_READCOMMITTED;
|
|
rgIsoLevel[5] = ISOLATIONLEVEL_REPEATABLEREAD;
|
|
rgIsoLevel[6] = ISOLATIONLEVEL_SERIALIZABLE;
|
|
rgIsoLevel[7] = ISOLATIONLEVEL_ISOLATED;
|
|
rgIsoLevel[8] = ISOLATIONLEVEL_UNSPECIFIED;
|
|
|
|
for (ulIndex=0;ulIndex<ulIsoNum;ulIndex++)
|
|
{
|
|
//begin transaction can not handle ISOLATIONLEVEL_UNSPECIFIED so don't try it
|
|
if (rgIsoLevel[ulIndex]==ISOLATIONLEVEL_UNSPECIFIED)
|
|
{
|
|
IsoLevel = ISOLATIONLEVEL_READCOMMITTED;
|
|
}
|
|
else
|
|
{
|
|
IsoLevel = rgIsoLevel[ulIndex];
|
|
}
|
|
|
|
//start a coordinated txn through dtc & join it
|
|
if (CHECK(m_pChgRowset1->StartCoordTxn(&pITransaction,IsoLevel), TRUE))
|
|
{
|
|
//get transactionjoin transaction object.
|
|
if (CHECK(m_pChgRowset1->GetTxnJoin(), S_OK))
|
|
{
|
|
if (CHECK(m_pChgRowset1->m_pITxnJoin->JoinTransaction ( pITransaction,
|
|
rgIsoLevel[ulIndex],
|
|
0,
|
|
NULL
|
|
), S_OK))
|
|
{
|
|
m_pChgRowset1->m_fTxnStarted = TRUE;
|
|
//Make sure the Txn Info is correct
|
|
VerifyTxnInfo(pITransaction, rgIsoLevel[ulIndex], &uow1);
|
|
|
|
//get transactionjoin transaction object.
|
|
if (CHECK(m_pChgRowset2->GetTxnJoin(), S_OK))
|
|
{
|
|
if (CHECK(m_pChgRowset2->m_pITxnJoin->JoinTransaction ( pITransaction,
|
|
ISOLATIONLEVEL_UNSPECIFIED,
|
|
0,
|
|
NULL
|
|
), S_OK))
|
|
{
|
|
m_pChgRowset2->m_fTxnStarted = TRUE;
|
|
//Make sure the Txn Info is correct
|
|
VerifyTxnInfo(pITransaction, ISOLATIONLEVEL_UNSPECIFIED, &uow2);
|
|
|
|
//Make sure the Unit of Work Identifiers are idenitical (same coord txn)
|
|
if (memcmp(uow1.rgb, uow2.rgb, sizeof(uow1.rgb)))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (pITransaction)
|
|
{
|
|
m_pChgRowset1->FreeCoordTxn(pITransaction);
|
|
pITransaction = NULL;
|
|
}
|
|
//free objects;
|
|
m_pChgRowset1->FreeJoinTxn();
|
|
m_pChgRowset2->FreeJoinTxn();
|
|
|
|
//Release each rowset and end all transactions
|
|
ReleaseAllRowsetsAndTxns();
|
|
}
|
|
|
|
fResults = TRUE;
|
|
CLEANUP:
|
|
if (fResults)
|
|
return TEST_PASS;
|
|
else
|
|
return TEST_FAIL;
|
|
}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(2)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc Chaos
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCIsoLevel::Variation_2()
|
|
{
|
|
HROW hRow = DB_NULL_HROW;
|
|
BOOL fResults = FALSE;
|
|
IRowset *pIRowset = NULL;
|
|
BOOL fReadCommitted = TRUE;
|
|
HRESULT hr = S_OK;
|
|
ITransaction *pITransaction = NULL;
|
|
|
|
//If no provider support for this isolation level, just return pass
|
|
if (!m_fChaos)
|
|
{
|
|
odtLog << wszNoProviderSupport << L"CHAOS" << wszNewLine;
|
|
return TEST_PASS;
|
|
}
|
|
|
|
//start coordinated txn & join it
|
|
if (CHECK(m_pChgRowset1->StartCoordTxn(&pITransaction,m_fIsoLevel), TRUE))
|
|
{
|
|
//get transactionjoin transaction object.
|
|
if (CHECK(m_pChgRowset1->GetTxnJoin(), S_OK))
|
|
{
|
|
//join MTS at Chaos Isolation Level
|
|
if (CHECK(m_pChgRowset1->m_pITxnJoin->JoinTransaction ( pITransaction,
|
|
ISOLATIONLEVEL_CHAOS,
|
|
0,
|
|
NULL
|
|
), S_OK))
|
|
{
|
|
m_pChgRowset1->m_fTxnStarted = TRUE;
|
|
|
|
//Make sure the Txn Info is correct
|
|
VerifyTxnInfo(pITransaction, ISOLATIONLEVEL_CHAOS);
|
|
|
|
//get 2nd transactionjoin transaction object.
|
|
if (CHECK(m_pChgRowset2->GetTxnJoin(), S_OK))
|
|
{
|
|
//join the coordinated txn from a 2nd session, ISOLATIONLEVEL_READCOMMITTED
|
|
hr=m_pChgRowset2->m_pITxnJoin->JoinTransaction ( pITransaction,
|
|
ISOLATIONLEVEL_READCOMMITTED,
|
|
0,
|
|
NULL
|
|
);
|
|
|
|
//if ISOLATIONLEVEL_READCOMMITTED unsupported
|
|
if (XACT_E_ISOLATIONLEVEL==hr)
|
|
{
|
|
//join the coordinated txn from a 2nd session, ISOLATIONLEVEL_READUNCOMMITTED
|
|
if(CHECK(m_pChgRowset2->m_pITxnJoin->JoinTransaction ( pITransaction,
|
|
ISOLATIONLEVEL_READUNCOMMITTED,
|
|
0,
|
|
NULL
|
|
),S_OK))
|
|
{
|
|
fReadCommitted = FALSE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//We should have succeeded if we support it
|
|
CHECK(m_hr, S_OK);
|
|
}
|
|
m_pChgRowset2->m_fTxnStarted = TRUE;
|
|
|
|
//if provider does not support IRowsetChange
|
|
if (!m_pChgRowset2->m_fChange)
|
|
{
|
|
if(!CHECK((m_pChgRowset2->m_pTable)->Insert(GetNextRowToInsert()), S_OK))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//Do something in txn
|
|
if(!COMPARE(Insert(m_pChgRowset2), TRUE))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
}
|
|
|
|
//But we shouldn't be able to see the change or touch it
|
|
//if we are at read committed on the second txn
|
|
if (fReadCommitted)
|
|
{
|
|
if (!COMPARE(FindChange(m_pChgRowset1), FALSE))
|
|
goto CLEANUP;
|
|
}
|
|
//We will be able to see the change if we are in read uncommitted mode
|
|
else
|
|
{
|
|
if (!COMPARE(FindChange(m_pChgRowset1), TRUE))
|
|
goto CLEANUP;
|
|
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
//Everything went OK if we got to here
|
|
fResults = TRUE;
|
|
CLEANUP:
|
|
m_pChgRowset1->FreeJoinTxn();
|
|
m_pChgRowset2->FreeJoinTxn();
|
|
if (pITransaction)
|
|
{
|
|
m_pChgRowset1->FreeCoordTxn(pITransaction);
|
|
pITransaction = NULL;
|
|
}
|
|
ReleaseAllRowsetsAndTxns();
|
|
SAFE_RELEASE(pIRowset);
|
|
if (fResults)
|
|
return TEST_PASS;
|
|
else
|
|
return TEST_FAIL;
|
|
}
|
|
// }}
|
|
|
|
// }}
|
|
// {{ TCW_TERMINATE_METHOD
|
|
//--------------------------------------------------------------------
|
|
// @mfunc TestCase Termination Routine
|
|
//
|
|
// @rdesc TRUE or FALSE
|
|
//
|
|
BOOL TCIsoLevel::Terminate()
|
|
{
|
|
// {{ TCW_TERM_BASECLASS_CHECK2
|
|
return(CTxnImmed::Terminate());
|
|
} // }}
|
|
// }}
|
|
// }}
|
|
|
|
// {{ TCW_TC_PROTOTYPE(TCEnListmentNULL)
|
|
//*-----------------------------------------------------------------------
|
|
//| Test Case: TCEnListmentNULL - Enlistment Testing
|
|
//| Created: 04/16/98
|
|
//*-----------------------------------------------------------------------
|
|
|
|
//--------------------------------------------------------------------
|
|
// @mfunc TestCase Initialization Routine
|
|
//
|
|
// @rdesc TRUE or FALSE
|
|
//
|
|
BOOL TCEnListmentNULL::Init()
|
|
{
|
|
// {{ TCW_INIT_BASECLASS_CHECK
|
|
if(CTxnImmed::Init())
|
|
// }}
|
|
{
|
|
//the jet engine (access) does not support distributed transactions
|
|
if (m_fOnAccess)
|
|
{
|
|
return TEST_SKIPPED;
|
|
}
|
|
else
|
|
{
|
|
return TEST_PASS;
|
|
}
|
|
}
|
|
return TEST_FAIL;
|
|
}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(1)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc Join-Commit-UnEnlist-reEnlist
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCEnListmentNULL::Variation_1()
|
|
{
|
|
BOOL fResults = FALSE;
|
|
HRESULT hr = S_OK;
|
|
ITransaction *pITransaction = NULL;
|
|
|
|
//start coordinated txn & join it
|
|
if (CHECK(m_pChgRowset1->StartCoordTxn(&pITransaction,m_fIsoLevel), TRUE))
|
|
{
|
|
//get transactionjoin transaction object.
|
|
if (CHECK(m_pChgRowset1->GetTxnJoin(), S_OK))
|
|
{
|
|
//join MTS
|
|
if (CHECK(m_pChgRowset1->m_pITxnJoin->JoinTransaction ( pITransaction,
|
|
m_fIsoLevel,
|
|
0,
|
|
NULL
|
|
), S_OK))
|
|
{
|
|
m_pChgRowset1->m_fTxnStarted = TRUE;
|
|
|
|
//end the mts coordinated txn, commit it, do not retain commit, zombies session
|
|
if (CHECK(pITransaction->Commit(FALSE, FALSE, FALSE), S_OK))
|
|
{
|
|
m_pChgRowset1->m_fTxnStarted = FALSE;
|
|
//unelinst from MTS
|
|
hr=m_pChgRowset1->m_pITxnJoin->JoinTransaction ( NULL,
|
|
m_fIsoLevel,
|
|
0,
|
|
NULL
|
|
);
|
|
if(S_OK==hr)
|
|
{
|
|
//rowset should be functional
|
|
if (!COMPARE(RowsetFunctional(m_pChgRowset1), TRUE))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
|
|
//clean up any open objects
|
|
m_pChgRowset1->ReleaseRowsetObject();
|
|
|
|
//re-join MTS, pITransaction is dead should get XACT_E_NOENLIST
|
|
if (CHECK(m_pChgRowset1->m_pITxnJoin->JoinTransaction ( pITransaction,
|
|
m_fIsoLevel,
|
|
0,
|
|
NULL
|
|
), XACT_E_NOENLIST))
|
|
{
|
|
fResults = TRUE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
CLEANUP:
|
|
//free objects;
|
|
m_pChgRowset1->FreeJoinTxn();
|
|
if (pITransaction)
|
|
{
|
|
m_pChgRowset1->FreeCoordTxn(pITransaction);
|
|
pITransaction = NULL;
|
|
}
|
|
return fResults;
|
|
}
|
|
// }}
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(2)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc Join-Abort-UnEnlist-reEnlist
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
// SESF_IN_TXN
|
|
int TCEnListmentNULL::Variation_2()
|
|
{
|
|
BOOL fResults = FALSE;
|
|
HRESULT hr = S_OK;
|
|
ITransaction *pITransaction = NULL;
|
|
|
|
//start coordinated txn & join it
|
|
if (CHECK(m_pChgRowset1->StartCoordTxn(&pITransaction,m_fIsoLevel), TRUE))
|
|
{
|
|
//get transactionjoin transaction object.
|
|
if (CHECK(m_pChgRowset1->GetTxnJoin(), S_OK))
|
|
{
|
|
//join MTS
|
|
if (CHECK(m_pChgRowset1->m_pITxnJoin->JoinTransaction ( pITransaction,
|
|
m_fIsoLevel,
|
|
0,
|
|
NULL
|
|
), S_OK))
|
|
{
|
|
m_pChgRowset1->m_fTxnStarted = TRUE;
|
|
//end the mts coordinated txn, abort it, txn not retained, zombies session
|
|
if (CHECK(pITransaction->Abort(NULL, FALSE, FALSE), S_OK))
|
|
{
|
|
m_pChgRowset1->m_fTxnStarted = FALSE;
|
|
//unelinst from MTS
|
|
hr=m_pChgRowset1->m_pITxnJoin->JoinTransaction ( NULL,
|
|
m_fIsoLevel,
|
|
0,
|
|
NULL
|
|
);
|
|
if(S_OK==hr)
|
|
{
|
|
//rowset should be functional
|
|
|
|
if (!COMPARE(RowsetFunctional(m_pChgRowset1), TRUE))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
//clean up any open objects
|
|
m_pChgRowset1->ReleaseRowsetObject();
|
|
|
|
//re-join MTS, pITransaction is dead should get XACT_E_NOENLIST
|
|
if (CHECK(m_pChgRowset1->m_pITxnJoin->JoinTransaction ( pITransaction,
|
|
m_fIsoLevel,
|
|
0,
|
|
NULL
|
|
), XACT_E_NOENLIST))
|
|
{
|
|
fResults = TRUE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
CLEANUP:
|
|
//free objects;
|
|
m_pChgRowset1->FreeJoinTxn();
|
|
if (pITransaction)
|
|
{
|
|
m_pChgRowset1->FreeCoordTxn(pITransaction);
|
|
pITransaction = NULL;
|
|
}
|
|
return fResults;
|
|
}
|
|
// }}
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(3)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc Back to back UnEnlists
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCEnListmentNULL::Variation_3()
|
|
{
|
|
BOOL fResults = TEST_FAIL;
|
|
HRESULT hr = S_OK;
|
|
ITransaction *pITransaction = NULL;
|
|
|
|
//start coordinated txn & join it
|
|
if (CHECK(m_pChgRowset1->StartCoordTxn(&pITransaction,m_fIsoLevel), TRUE))
|
|
{
|
|
//get transactionjoin transaction object.
|
|
if (CHECK(m_pChgRowset1->GetTxnJoin(), S_OK))
|
|
{
|
|
//join MTS
|
|
if (CHECK(m_pChgRowset1->m_pITxnJoin->JoinTransaction ( pITransaction,
|
|
m_fIsoLevel,
|
|
0,
|
|
NULL
|
|
), S_OK))
|
|
{
|
|
m_pChgRowset1->m_fTxnStarted = TRUE;
|
|
|
|
//end the mts coordinated txn, abort it, do not retain abort, zombies session
|
|
if (CHECK(pITransaction->Abort(NULL, FALSE, FALSE), S_OK))
|
|
{
|
|
m_pChgRowset1->m_fTxnStarted = FALSE;
|
|
//unelinst from MTS
|
|
hr=m_pChgRowset1->m_pITxnJoin->JoinTransaction ( NULL,
|
|
m_fIsoLevel,
|
|
0,
|
|
NULL
|
|
);
|
|
if(S_OK==hr)
|
|
{
|
|
//no pending work, should return S_OK
|
|
hr=m_pChgRowset1->m_pITxnJoin->JoinTransaction ( NULL,
|
|
m_fIsoLevel,
|
|
0,
|
|
NULL
|
|
);
|
|
if(S_OK==hr )
|
|
{
|
|
fResults = TRUE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
//free objects;
|
|
m_pChgRowset1->FreeJoinTxn();
|
|
if (pITransaction)
|
|
{
|
|
m_pChgRowset1->FreeCoordTxn(pITransaction);
|
|
pITransaction = NULL;
|
|
}
|
|
return fResults;
|
|
}
|
|
// }}
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(4)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc UnEnList but no txn
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCEnListmentNULL::Variation_4()
|
|
{
|
|
BOOL fResults = FALSE;
|
|
HRESULT hr = S_OK;
|
|
ITransaction *pITransaction = NULL;
|
|
|
|
//start coordinated txn & join it
|
|
if (CHECK(m_pChgRowset1->StartCoordTxn(&pITransaction,m_fIsoLevel), TRUE))
|
|
{
|
|
//get transactionjoin transaction object.
|
|
if (CHECK(m_pChgRowset1->GetTxnJoin(), S_OK))
|
|
{
|
|
//no pending work, should return S_OK
|
|
hr=m_pChgRowset1->m_pITxnJoin->JoinTransaction ( NULL,
|
|
m_fIsoLevel,
|
|
0,
|
|
NULL
|
|
);
|
|
if(S_OK==hr )
|
|
{
|
|
fResults=TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
//free objects;
|
|
m_pChgRowset1->FreeJoinTxn();
|
|
if (pITransaction)
|
|
{
|
|
m_pChgRowset1->FreeCoordTxn(pITransaction);
|
|
pITransaction = NULL;
|
|
}
|
|
|
|
return fResults;
|
|
}
|
|
// }}
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(5)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc Join Committed session with new MTSTxn
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCEnListmentNULL::Variation_5()
|
|
{
|
|
BOOL fResults = FALSE;
|
|
HRESULT hr = S_OK;
|
|
ITransaction *pITransaction = NULL;
|
|
|
|
//start coordinated txn & join it
|
|
if (CHECK(m_pChgRowset1->StartCoordTxn(&pITransaction,m_fIsoLevel), TRUE))
|
|
{
|
|
//get transactionjoin transaction object.
|
|
if (CHECK(m_pChgRowset1->GetTxnJoin(), S_OK))
|
|
{
|
|
//join MTS
|
|
if (CHECK(m_pChgRowset1->m_pITxnJoin->JoinTransaction ( pITransaction,
|
|
m_fIsoLevel,
|
|
0,
|
|
NULL
|
|
), S_OK))
|
|
{
|
|
m_pChgRowset1->m_fTxnStarted = TRUE;
|
|
//end the mts coordinated txn, commit it, do not retain commit, zombies session
|
|
if (CHECK(pITransaction->Commit(FALSE, FALSE, FALSE), S_OK))
|
|
{
|
|
m_pChgRowset1->m_fTxnStarted = FALSE;
|
|
|
|
//clean up any open objects
|
|
m_pChgRowset1->ReleaseRowsetObject();
|
|
|
|
//free the MTS Txn pointer
|
|
if (pITransaction)
|
|
{
|
|
m_pChgRowset1->FreeCoordTxn(pITransaction);
|
|
pITransaction = NULL;
|
|
}
|
|
|
|
//start another coordinated txn
|
|
if (CHECK(m_pChgRowset1->StartCoordTxn(&pITransaction,m_fIsoLevel), TRUE))
|
|
{
|
|
//Rejoin MTS
|
|
if (CHECK(m_pChgRowset1->m_pITxnJoin->JoinTransaction ( pITransaction,
|
|
m_fIsoLevel,
|
|
0,
|
|
NULL
|
|
), S_OK))
|
|
{
|
|
m_pChgRowset1->m_fTxnStarted = TRUE;
|
|
|
|
if (COMPARE(RowsetFunctional(m_pChgRowset1), TRUE))
|
|
{
|
|
//end the mts coordinated txn, commit it, do not retain commit, zombies session
|
|
if (CHECK(pITransaction->Commit(FALSE, FALSE, FALSE), S_OK))
|
|
{
|
|
m_pChgRowset1->m_fTxnStarted = FALSE;
|
|
//unelinst from MTS
|
|
hr=m_pChgRowset1->m_pITxnJoin->JoinTransaction ( NULL,
|
|
m_fIsoLevel,
|
|
0,
|
|
NULL
|
|
);
|
|
if(S_OK==hr)
|
|
{
|
|
fResults = TRUE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
//CLEANUP:
|
|
//free objects;
|
|
m_pChgRowset1->FreeJoinTxn();
|
|
if (pITransaction)
|
|
{
|
|
m_pChgRowset1->FreeCoordTxn(pITransaction);
|
|
pITransaction = NULL;
|
|
}
|
|
ReleaseAllRowsetsAndTxns();
|
|
|
|
return fResults;
|
|
}
|
|
// }}
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(6)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc Join Aborted session with new MTSTxn
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCEnListmentNULL::Variation_6()
|
|
{
|
|
BOOL fResults = FALSE;
|
|
HRESULT hr = S_OK;
|
|
ITransaction *pITransaction = NULL;
|
|
|
|
//start coordinated txn & join it
|
|
if (CHECK(m_pChgRowset1->StartCoordTxn(&pITransaction,m_fIsoLevel), TRUE))
|
|
{
|
|
//get transactionjoin transaction object.
|
|
if (CHECK(m_pChgRowset1->GetTxnJoin(), S_OK))
|
|
{
|
|
//join MTS
|
|
if (CHECK(m_pChgRowset1->m_pITxnJoin->JoinTransaction ( pITransaction,
|
|
m_fIsoLevel,
|
|
0,
|
|
NULL
|
|
), S_OK))
|
|
{
|
|
m_pChgRowset1->m_fTxnStarted = TRUE;
|
|
|
|
//end the mts coordinated txn, abort it, do not retain abort, zombies session
|
|
if (CHECK(pITransaction->Abort(NULL, FALSE, FALSE), S_OK))
|
|
{
|
|
m_pChgRowset1->m_fTxnStarted = FALSE;
|
|
|
|
//clean up any open objects
|
|
m_pChgRowset1->ReleaseRowsetObject();
|
|
|
|
//free the MTS Txn pointer
|
|
if (pITransaction)
|
|
{
|
|
m_pChgRowset1->FreeCoordTxn(pITransaction);
|
|
pITransaction = NULL;
|
|
}
|
|
//start another coordinated txn
|
|
if (CHECK(m_pChgRowset1->StartCoordTxn(&pITransaction,m_fIsoLevel), TRUE))
|
|
{
|
|
//Rejoin MTS
|
|
if (CHECK(m_pChgRowset1->m_pITxnJoin->JoinTransaction ( pITransaction,
|
|
m_fIsoLevel,
|
|
0,
|
|
NULL
|
|
), S_OK))
|
|
{
|
|
m_pChgRowset1->m_fTxnStarted = TRUE;
|
|
|
|
if (COMPARE(RowsetFunctional(m_pChgRowset1), TRUE))
|
|
{
|
|
//end the mts coordinated txn, abort it, do not retain abort, zombies session
|
|
if (CHECK(pITransaction->Abort(NULL, FALSE, FALSE), S_OK))
|
|
{
|
|
//unelinst from MTS
|
|
hr=m_pChgRowset1->m_pITxnJoin->JoinTransaction ( NULL,
|
|
m_fIsoLevel,
|
|
0,
|
|
NULL
|
|
);
|
|
if(S_OK==hr)
|
|
{
|
|
fResults = TRUE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
//free objects;
|
|
m_pChgRowset1->FreeJoinTxn();
|
|
if (pITransaction)
|
|
{
|
|
m_pChgRowset1->FreeCoordTxn(pITransaction);
|
|
pITransaction = NULL;
|
|
}
|
|
ReleaseAllRowsetsAndTxns();
|
|
|
|
return fResults;
|
|
}
|
|
// }}
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(7)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc UnEnlists with pending work
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCEnListmentNULL::Variation_7()
|
|
{
|
|
BOOL fResults = TEST_SKIPPED;
|
|
HRESULT hr = S_OK;
|
|
ITransaction *pITransaction = NULL;
|
|
|
|
//this variation just blocks on sql server so it is commented out so the test does not
|
|
//hang when run against sql server
|
|
|
|
if(gfBlocked)
|
|
{
|
|
return fResults;
|
|
}
|
|
fResults = TEST_PASS;
|
|
|
|
//start coordinated txn & join it
|
|
if (CHECK(m_pChgRowset1->StartCoordTxn(&pITransaction,m_fIsoLevel), TRUE))
|
|
{
|
|
//get transactionjoin transaction object.
|
|
if (CHECK(m_pChgRowset1->GetTxnJoin(), S_OK))
|
|
{
|
|
//join MTS
|
|
if (CHECK(m_pChgRowset1->m_pITxnJoin->JoinTransaction ( pITransaction,
|
|
m_fIsoLevel,
|
|
0,
|
|
NULL
|
|
), S_OK))
|
|
{
|
|
m_pChgRowset1->m_fTxnStarted = TRUE;
|
|
|
|
//make something pending on the txn
|
|
//if provider does not support IRowsetChange
|
|
if (!m_pChgRowset1->m_fChange)
|
|
{
|
|
//Do something in txn
|
|
if(!CHECK((m_pChgRowset1->m_pTable)->Insert(GetNextRowToInsert()), S_OK))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//Do something in txn
|
|
if(!COMPARE(Insert(m_pChgRowset1), TRUE))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
}
|
|
|
|
//pending work, should return S_OK but might return XACT_E_XTIONEXISTS
|
|
hr = m_pChgRowset1->m_pITxnJoin->JoinTransaction ( NULL,
|
|
m_fIsoLevel,
|
|
0,
|
|
NULL
|
|
);
|
|
|
|
if (S_OK!=hr && XACT_E_XTIONEXISTS!=hr)
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
|
|
//end the mts coordinated txn, abort it, do not retain abort, zombies session
|
|
if (CHECK(pITransaction->Abort(NULL, FALSE, FALSE), S_OK))
|
|
{
|
|
//unenlist again from MTS in case above unenlistment returned XACT_E_XTIONEXISTS
|
|
hr=m_pChgRowset1->m_pITxnJoin->JoinTransaction ( NULL,
|
|
m_fIsoLevel,
|
|
0,
|
|
NULL
|
|
);
|
|
if(S_OK==hr)
|
|
{
|
|
fResults = TRUE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
CLEANUP:
|
|
//free objects;
|
|
ReleaseAllRowsetsAndTxns();
|
|
m_pChgRowset1->FreeJoinTxn();
|
|
if (pITransaction)
|
|
{
|
|
m_pChgRowset1->FreeCoordTxn(pITransaction);
|
|
pITransaction = NULL;
|
|
}
|
|
|
|
return fResults;
|
|
}
|
|
// }}
|
|
|
|
|
|
BOOL TCEnListmentNULL::Terminate()
|
|
{
|
|
// {{ TCW_TERM_BASECLASS_CHECK2
|
|
return(CTxnImmed::Terminate());
|
|
} // }}
|
|
// }}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_TC_PROTOTYPE(TCEnListment)
|
|
//*-----------------------------------------------------------------------
|
|
//| Test Case: TCEnListment - Enlistment Testing
|
|
//| Created: 04/16/98
|
|
//*-----------------------------------------------------------------------
|
|
|
|
//--------------------------------------------------------------------
|
|
// @mfunc TestCase Initialization Routine
|
|
//
|
|
// @rdesc TRUE or FALSE
|
|
//
|
|
BOOL TCEnListment::Init()
|
|
{
|
|
// {{ TCW_INIT_BASECLASS_CHECK
|
|
if(CTxnImmed::Init())
|
|
// }}
|
|
{
|
|
//the jet engine (access) does not support distributed transactions
|
|
if (m_fOnAccess)
|
|
{
|
|
return TEST_SKIPPED;
|
|
}
|
|
else
|
|
{
|
|
return TEST_PASS;
|
|
}
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(1)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc Join-Commit-reEnlist
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCEnListment::Variation_1()
|
|
{
|
|
BOOL fResults = FALSE;
|
|
HRESULT hr = S_OK;
|
|
ITransaction *pITransaction = NULL;
|
|
|
|
//start coordinated txn & join it
|
|
if (CHECK(m_pChgRowset1->StartCoordTxn(&pITransaction,m_fIsoLevel), TRUE))
|
|
{
|
|
//get transactionjoin transaction object.
|
|
if (CHECK(m_pChgRowset1->GetTxnJoin(), S_OK))
|
|
{
|
|
//join MTS
|
|
if (CHECK(m_pChgRowset1->m_pITxnJoin->JoinTransaction ( pITransaction,
|
|
m_fIsoLevel,
|
|
0,
|
|
NULL
|
|
), S_OK))
|
|
{
|
|
m_pChgRowset1->m_fTxnStarted = TRUE;
|
|
|
|
//end the mts coordinated txn, commit it, zombies session
|
|
if (CHECK(pITransaction->Commit(FALSE, FALSE, FALSE), S_OK))
|
|
{
|
|
|
|
m_pChgRowset1->m_fTxnStarted = FALSE;
|
|
//pending work, should return XACT_E_XTIONEXISTS
|
|
if (!CHECK(m_pChgRowset1->m_pITxnJoin->JoinTransaction ( NULL,
|
|
m_fIsoLevel,
|
|
0,
|
|
NULL
|
|
),S_OK)){}
|
|
|
|
//clean up any open objects
|
|
m_pChgRowset1->ReleaseRowsetObject();
|
|
|
|
//re-elinst from MTS
|
|
if (CHECK(m_pChgRowset1->m_pITxnJoin->JoinTransaction ( pITransaction,
|
|
m_fIsoLevel,
|
|
0,
|
|
NULL
|
|
), XACT_E_NOENLIST))
|
|
{
|
|
fResults = TRUE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//free objects;
|
|
ReleaseAllRowsetsAndTxns();
|
|
m_pChgRowset1->FreeJoinTxn();
|
|
if (pITransaction)
|
|
{
|
|
m_pChgRowset1->FreeCoordTxn(pITransaction);
|
|
pITransaction = NULL;
|
|
}
|
|
return fResults;
|
|
}
|
|
// }}
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(2)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc Join-Abort-reEnlist
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCEnListment::Variation_2()
|
|
{
|
|
BOOL fResults = FALSE;
|
|
HRESULT hr = S_OK;
|
|
ITransaction *pITransaction = NULL;
|
|
|
|
//start coordinated txn & join it
|
|
if (CHECK(m_pChgRowset1->StartCoordTxn(&pITransaction,m_fIsoLevel), TRUE))
|
|
{
|
|
//get transactionjoin transaction object.
|
|
if (CHECK(m_pChgRowset1->GetTxnJoin(), S_OK))
|
|
{
|
|
//join MTS
|
|
if (CHECK(m_pChgRowset1->m_pITxnJoin->JoinTransaction ( pITransaction,
|
|
m_fIsoLevel,
|
|
0,
|
|
NULL
|
|
), S_OK))
|
|
{
|
|
m_pChgRowset1->m_fTxnStarted = TRUE;
|
|
|
|
//end the mts coordinated txn, abort it, zombies session
|
|
if (CHECK(pITransaction->Abort(NULL, FALSE, FALSE), S_OK))
|
|
{
|
|
m_pChgRowset1->m_fTxnStarted = FALSE;
|
|
//unelinst from MTS
|
|
if (CHECK(m_pChgRowset1->m_pITxnJoin->JoinTransaction ( pITransaction,
|
|
m_fIsoLevel,
|
|
0,
|
|
NULL
|
|
), XACT_E_NOENLIST))
|
|
{
|
|
fResults = TRUE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//free objects;
|
|
ReleaseAllRowsetsAndTxns();
|
|
m_pChgRowset1->FreeJoinTxn();
|
|
if (pITransaction)
|
|
{
|
|
m_pChgRowset1->FreeCoordTxn(pITransaction);
|
|
pITransaction = NULL;
|
|
}
|
|
return fResults;
|
|
}
|
|
// }}
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(3)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc Back to back Enlists
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCEnListment::Variation_3()
|
|
{
|
|
BOOL fResults = TEST_FAIL;
|
|
HRESULT hr = S_OK;
|
|
ITransaction *pITransaction = NULL;
|
|
|
|
if(gfBlocked)
|
|
{
|
|
return TEST_SKIPPED;
|
|
}
|
|
|
|
//start coordinated txn & join it
|
|
if (CHECK(m_pChgRowset1->StartCoordTxn(&pITransaction,m_fIsoLevel), TRUE))
|
|
{
|
|
//get transactionjoin transaction object.
|
|
if (CHECK(m_pChgRowset1->GetTxnJoin(), S_OK))
|
|
{
|
|
//join MTS
|
|
if (CHECK(m_pChgRowset1->m_pITxnJoin->JoinTransaction ( pITransaction,
|
|
m_fIsoLevel,
|
|
0,
|
|
NULL
|
|
), S_OK))
|
|
{
|
|
m_pChgRowset1->m_fTxnStarted = TRUE;
|
|
//unelinst from MTS
|
|
if (CHECK(m_pChgRowset1->m_pITxnJoin->JoinTransaction ( pITransaction,
|
|
m_fIsoLevel,
|
|
0,
|
|
NULL
|
|
), XACT_E_XTIONEXISTS))
|
|
{
|
|
fResults = TRUE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//free objects;
|
|
ReleaseAllRowsetsAndTxns();
|
|
m_pChgRowset1->FreeJoinTxn();
|
|
if (pITransaction)
|
|
{
|
|
m_pChgRowset1->FreeCoordTxn(pITransaction);
|
|
pITransaction = NULL;
|
|
}
|
|
return fResults;
|
|
}
|
|
// }}
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(4)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc mfunc Test MTS after Commit
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCEnListment::Variation_4()
|
|
{
|
|
BOOL fResults = FALSE;
|
|
HRESULT hr = S_OK;
|
|
ITransaction *pITransaction = NULL;
|
|
XACTTRANSINFO TXNInfo;
|
|
|
|
//start coordinated txn & join it
|
|
if (CHECK(m_pChgRowset1->StartCoordTxn(&pITransaction,m_fIsoLevel), TRUE))
|
|
{
|
|
//get transactionjoin transaction object.
|
|
if (CHECK(m_pChgRowset1->GetTxnJoin(), S_OK))
|
|
{
|
|
//join MTS
|
|
if (CHECK(m_pChgRowset1->m_pITxnJoin->JoinTransaction ( pITransaction,
|
|
m_fIsoLevel,
|
|
0,
|
|
NULL
|
|
), S_OK))
|
|
{
|
|
m_pChgRowset1->m_fTxnStarted = TRUE;
|
|
//Now commit it, zombies session
|
|
if (CHECK(pITransaction->Commit(FALSE, FALSE, FALSE), S_OK))
|
|
{
|
|
m_pChgRowset1->m_fTxnStarted = FALSE;
|
|
if (CHECK(pITransaction->Commit(FALSE, FALSE, FALSE), XACT_E_NOTRANSACTION))
|
|
{
|
|
if (CHECK(pITransaction->GetTransactionInfo(&TXNInfo), XACT_E_NOTRANSACTION))
|
|
{
|
|
fResults = TRUE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//free objects;
|
|
ReleaseAllRowsetsAndTxns();
|
|
m_pChgRowset1->FreeJoinTxn();
|
|
if (pITransaction)
|
|
{
|
|
m_pChgRowset1->FreeCoordTxn(pITransaction);
|
|
pITransaction = NULL;
|
|
}
|
|
|
|
return fResults;}
|
|
// }}
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(5)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc Test MTS after Abort
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCEnListment::Variation_5()
|
|
{
|
|
BOOL fResults = FALSE;
|
|
HRESULT hr = S_OK;
|
|
ITransaction *pITransaction = NULL;
|
|
XACTTRANSINFO TXNInfo;
|
|
|
|
//start coordinated txn & join it
|
|
if (CHECK(m_pChgRowset1->StartCoordTxn(&pITransaction,m_fIsoLevel), TRUE))
|
|
{
|
|
//get transactionjoin transaction object.
|
|
if (CHECK(m_pChgRowset1->GetTxnJoin(), S_OK))
|
|
{
|
|
//join MTS
|
|
if (CHECK(m_pChgRowset1->m_pITxnJoin->JoinTransaction ( pITransaction,
|
|
m_fIsoLevel,
|
|
0,
|
|
NULL
|
|
), S_OK))
|
|
{
|
|
m_pChgRowset1->m_fTxnStarted = TRUE;
|
|
//Now commit it, zombies session
|
|
if (CHECK(pITransaction->Abort(NULL, FALSE, FALSE), S_OK))
|
|
{
|
|
hr=pITransaction->Abort(NULL, FALSE, FALSE);
|
|
if (XACT_E_NOTRANSACTION==hr || XACT_S_ABORTING==hr)
|
|
{
|
|
if (CHECK(pITransaction->GetTransactionInfo(&TXNInfo), XACT_E_NOTRANSACTION))
|
|
{
|
|
fResults = TRUE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//free objects;
|
|
ReleaseAllRowsetsAndTxns();
|
|
m_pChgRowset1->FreeJoinTxn();
|
|
if (pITransaction)
|
|
{
|
|
m_pChgRowset1->FreeCoordTxn(pITransaction);
|
|
pITransaction = NULL;
|
|
}
|
|
|
|
return fResults;
|
|
}
|
|
// }}
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(6)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc Back to back Enlists (different Txns)
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCEnListment::Variation_6()
|
|
{
|
|
BOOL fResults = TEST_FAIL;
|
|
HRESULT hr = S_OK;
|
|
ITransaction *pITransaction1 = NULL;
|
|
ITransaction *pITransaction2 = NULL;
|
|
|
|
|
|
if(gfBlocked)
|
|
{
|
|
return TEST_SKIPPED;
|
|
}
|
|
|
|
//start coordinated txn & join it
|
|
if (CHECK(m_pChgRowset1->StartCoordTxn(&pITransaction1,m_fIsoLevel), TRUE))
|
|
{
|
|
//get transactionjoin transaction object.
|
|
if (CHECK(m_pChgRowset1->GetTxnJoin(), S_OK))
|
|
{
|
|
//start another coordinated txn
|
|
if (CHECK(m_pChgRowset1->StartCoordTxn(&pITransaction2,m_fIsoLevel), TRUE))
|
|
{
|
|
//join MTS
|
|
if (CHECK(m_pChgRowset1->m_pITxnJoin->JoinTransaction ( pITransaction1,
|
|
m_fIsoLevel,
|
|
0,
|
|
NULL
|
|
), S_OK))
|
|
{
|
|
//unelinst from MTS
|
|
if (CHECK(m_pChgRowset1->m_pITxnJoin->JoinTransaction ( pITransaction2,
|
|
m_fIsoLevel,
|
|
0,
|
|
NULL
|
|
), XACT_E_XTIONEXISTS))
|
|
{
|
|
fResults = TRUE;
|
|
}
|
|
}
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
//free objects;
|
|
m_pChgRowset1->FreeJoinTxn();
|
|
ReleaseAllRowsetsAndTxns();
|
|
if (pITransaction1)
|
|
{
|
|
m_pChgRowset1->FreeCoordTxn(pITransaction1);
|
|
pITransaction1 = NULL;
|
|
}
|
|
if (pITransaction2)
|
|
{
|
|
m_pChgRowset1->FreeCoordTxn(pITransaction2);
|
|
pITransaction2 = NULL;
|
|
}
|
|
|
|
return fResults;
|
|
}
|
|
// }}
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(7)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc Join-Commit-unEnlist-reEnlist
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCEnListment::Variation_7()
|
|
{
|
|
BOOL fResults = FALSE;
|
|
HRESULT hr = S_OK;
|
|
ITransaction *pITransaction1 = NULL;
|
|
ITransaction *pITransaction2 = NULL;
|
|
|
|
//start coordinated txn & join it
|
|
if (CHECK(m_pChgRowset1->StartCoordTxn(&pITransaction1,m_fIsoLevel), TRUE))
|
|
{
|
|
//get transactionjoin transaction object.
|
|
if (CHECK(m_pChgRowset1->GetTxnJoin(), S_OK))
|
|
{
|
|
//join MTS
|
|
if (CHECK(m_pChgRowset1->m_pITxnJoin->JoinTransaction ( pITransaction1,
|
|
m_fIsoLevel,
|
|
0,
|
|
NULL
|
|
), S_OK))
|
|
{
|
|
m_pChgRowset1->m_fTxnStarted = TRUE;
|
|
|
|
//end the mts coordinated txn, commit it, zombies session
|
|
if (CHECK(pITransaction1->Commit(FALSE, FALSE, FALSE), S_OK))
|
|
{
|
|
|
|
m_pChgRowset1->m_fTxnStarted = FALSE;
|
|
//UnEnlist into MTS
|
|
if (!CHECK(m_pChgRowset1->m_pITxnJoin->JoinTransaction ( NULL,
|
|
m_fIsoLevel,
|
|
0,
|
|
NULL
|
|
),S_OK)){}
|
|
|
|
//clean up any open objects
|
|
m_pChgRowset1->ReleaseRowsetObject();
|
|
|
|
//start 2nd coordinated (DTC) txn
|
|
if (CHECK(m_pChgRowset1->StartCoordTxn(&pITransaction2,m_fIsoLevel), TRUE))
|
|
{
|
|
//re-elinst session in new DTC txn
|
|
if (CHECK(m_pChgRowset1->m_pITxnJoin->JoinTransaction ( pITransaction2,
|
|
m_fIsoLevel,
|
|
0,
|
|
NULL
|
|
), S_OK))
|
|
{
|
|
m_pChgRowset1->m_fTxnStarted = TRUE;
|
|
|
|
if (COMPARE(RowsetFunctional(m_pChgRowset1), TRUE))
|
|
{
|
|
//end the mts coordinated txn, commit it, do not retain commit, zombies session
|
|
if (CHECK(pITransaction2->Commit(FALSE, FALSE, FALSE), S_OK))
|
|
{
|
|
//clean up any open objects, can't have any open statements when
|
|
//unenlisting because some provider might disconnect on unenlistment
|
|
m_pChgRowset1->ReleaseRowsetObject();
|
|
|
|
m_pChgRowset1->m_fTxnStarted = FALSE;
|
|
//unelinst from MTS
|
|
hr=m_pChgRowset1->m_pITxnJoin->JoinTransaction ( NULL,
|
|
m_fIsoLevel,
|
|
0,
|
|
NULL
|
|
);
|
|
//why is XACT_E_XTIONEXISTS acceptable here?
|
|
// if(XACT_E_XTIONEXISTS==hr)
|
|
// {
|
|
// fResults=TRUE;
|
|
// goto CLEANUP;
|
|
// }
|
|
if(S_OK==hr)
|
|
{
|
|
fResults = TRUE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//free objects;
|
|
ReleaseAllRowsetsAndTxns();
|
|
m_pChgRowset1->FreeJoinTxn();
|
|
if (pITransaction1)
|
|
{
|
|
m_pChgRowset1->FreeCoordTxn(pITransaction1);
|
|
pITransaction1 = NULL;
|
|
}
|
|
if (pITransaction2)
|
|
{
|
|
m_pChgRowset1->FreeCoordTxn(pITransaction2);
|
|
pITransaction2 = NULL;
|
|
}
|
|
return fResults;
|
|
}
|
|
// }}
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(8)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc Join before firehose mode
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCEnListment::Variation_8()
|
|
{
|
|
BOOL fResults = FALSE;
|
|
HRESULT hr = S_OK;
|
|
ITransaction *pITransaction = NULL;
|
|
ICommand *pICommand2 = NULL;
|
|
DBPROPSET DBPropSet;
|
|
DBPROP DBProp;
|
|
|
|
|
|
//set a prop to insure a forward only curosr
|
|
DBPropSet.rgProperties = &DBProp;
|
|
DBPropSet.cProperties = 1;
|
|
DBPropSet.guidPropertySet = DBPROPSET_ROWSET;
|
|
|
|
DBProp.dwPropertyID = DBPROP_CANSCROLLBACKWARDS;
|
|
DBProp.dwOptions = DBPROPOPTIONS_REQUIRED;
|
|
DBProp.colid = DB_NULLID;
|
|
DBProp.vValue.vt = VT_BOOL;
|
|
V_BOOL(&(DBProp.vValue)) = VARIANT_FALSE;
|
|
|
|
//set props
|
|
hr = m_pChgRowset1->SetRowsetProperties(&DBPropSet, 1);
|
|
|
|
//get a rowset through the command
|
|
m_pChgRowset1->CreateRowsetObject();
|
|
|
|
//Another hstmt should work, either on the same hdbc or a new one
|
|
if (!CHECK(m_pChgRowset1->m_pIDBCreateCommand->CreateCommand(NULL, IID_ICommand, (IUnknown **)&pICommand2), S_OK))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
|
|
//start coordinated txn & join it
|
|
if (CHECK(m_pChgRowset1->StartCoordTxn(&pITransaction,m_fIsoLevel), TRUE))
|
|
{
|
|
//get transactionjoin transaction object.
|
|
if (CHECK(m_pChgRowset1->GetTxnJoin(), S_OK))
|
|
{
|
|
//join MTS
|
|
TEST2C_(m_pChgRowset1->m_pITxnJoin->JoinTransaction ( pITransaction,
|
|
m_fIsoLevel,
|
|
0,
|
|
NULL
|
|
), XACT_E_CONNECTION_REQUEST_DENIED, E_FAIL);
|
|
m_pChgRowset1->m_fTxnStarted = TRUE;
|
|
|
|
//end the mts coordinated txn, commit it, zombies session
|
|
if (CHECK(pITransaction->Commit(FALSE, FALSE, FALSE), S_OK))
|
|
{
|
|
fResults = TRUE;
|
|
}
|
|
}
|
|
}
|
|
CLEANUP:
|
|
//free objects;
|
|
ReleaseAllRowsetsAndTxns();
|
|
SAFE_RELEASE(pICommand2);
|
|
m_pChgRowset1->FreeJoinTxn();
|
|
if (pITransaction)
|
|
{
|
|
m_pChgRowset1->FreeCoordTxn(pITransaction);
|
|
pITransaction = NULL;
|
|
}
|
|
return fResults;
|
|
}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(9)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc Join after firehose mode
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCEnListment::Variation_9()
|
|
{
|
|
BOOL fResults = TEST_FAIL;
|
|
HRESULT hr = S_OK;
|
|
ITransaction *pITransaction = NULL;
|
|
ICommand *pICommand2 = NULL;
|
|
DBPROPSET DBPropSet;
|
|
DBPROP DBProp;
|
|
IRowsetChange *pIRowsetChange = NULL;
|
|
IRowsetChange *pIRowsetChange2 = NULL;
|
|
|
|
|
|
//set a prop to insure a forward only curosr
|
|
DBPropSet.rgProperties = &DBProp;
|
|
DBPropSet.cProperties = 1;
|
|
DBPropSet.guidPropertySet = DBPROPSET_ROWSET;
|
|
|
|
DBProp.dwPropertyID = DBPROP_CANSCROLLBACKWARDS;
|
|
DBProp.dwOptions = DBPROPOPTIONS_REQUIRED;
|
|
DBProp.colid = DB_NULLID;
|
|
DBProp.vValue.vt = VT_BOOL;
|
|
V_BOOL(&(DBProp.vValue)) = VARIANT_FALSE;
|
|
|
|
if(gfBlocked)
|
|
{
|
|
return TEST_SKIPPED;
|
|
}
|
|
|
|
//set props
|
|
hr = m_pChgRowset1->SetRowsetProperties(&DBPropSet, 1);
|
|
|
|
//start coordinated txn & join it
|
|
if (CHECK(m_pChgRowset1->StartCoordTxn(&pITransaction,m_fIsoLevel), TRUE))
|
|
{
|
|
//get transactionjoin transaction object.
|
|
if (CHECK(m_pChgRowset1->GetTxnJoin(), S_OK))
|
|
{
|
|
//join MTS
|
|
if (CHECK(m_pChgRowset1->m_pITxnJoin->JoinTransaction ( pITransaction,
|
|
m_fIsoLevel,
|
|
0,
|
|
NULL
|
|
), S_OK))
|
|
{
|
|
m_pChgRowset1->m_fTxnStarted = TRUE;
|
|
|
|
//get a rowset through the command
|
|
m_pChgRowset1->CreateRowsetObject();
|
|
|
|
//Another command here might or might not work
|
|
//some providers might not allow another command here if the only way to get the command
|
|
//is by implicitly opening another connection because that under-the-covers connection
|
|
//will not be transacted
|
|
//if the command is allowed then that means the second command object is now also enlisted
|
|
//in the transactoin
|
|
hr = m_pChgRowset1->m_pIDBCreateCommand->CreateCommand(NULL, IID_ICommand, (IUnknown **)&pICommand2);
|
|
|
|
m_pChgRowset1->ReleaseRowsetObject();
|
|
|
|
//if the second command object is not allowed then skip;
|
|
if (S_OK==hr)
|
|
{
|
|
//end the mts coordinated txn, commit it, zombies session
|
|
if (CHECK(pITransaction->Commit(FALSE, FALSE, FALSE), S_OK))
|
|
{
|
|
//test to see if both command objects are under the global transaction
|
|
//since the CreateCommand passed, if we are here both QI should zombie on the commit
|
|
// CHECK(VerifyInterface(m_pChgRowset1->m_pIAccessor, IID_IRowsetChange, ROWSET_INTERFACE,(IUnknown **)&pIRowsetChange),E_FAIL);
|
|
// CHECK(VerifyInterface(pICommand2, IID_IRowsetChange, ROWSET_INTERFACE,(IUnknown **)&pIRowsetChange2),E_FAIL);
|
|
fResults = TEST_PASS;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
fResults = TEST_SKIPPED;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//free objects;
|
|
ReleaseAllRowsetsAndTxns();
|
|
SAFE_RELEASE(pICommand2);
|
|
SAFE_RELEASE(pIRowsetChange);
|
|
SAFE_RELEASE(pIRowsetChange2);
|
|
m_pChgRowset1->FreeJoinTxn();
|
|
if (pITransaction)
|
|
{
|
|
m_pChgRowset1->FreeCoordTxn(pITransaction);
|
|
pITransaction = NULL;
|
|
}
|
|
return fResults;
|
|
}
|
|
// }}
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(10)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc commit with 2 commands open
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCEnListment::Variation_10()
|
|
{
|
|
BOOL fResults = TEST_FAIL;
|
|
HRESULT hr = S_OK;
|
|
ITransaction *pITransaction = NULL;
|
|
ICommand *pICommand2 = NULL;
|
|
IRowsetChange *pIRowsetChange = NULL;
|
|
IRowsetChange *pIRowsetChange2 = NULL;
|
|
HACCESSOR hAccessor = NULL;
|
|
void* pData = NULL;
|
|
DBCOUNTITEM cBindings = 0;
|
|
DBBINDING *rgBindings = NULL;
|
|
|
|
if(gfBlocked)
|
|
{
|
|
return TEST_SKIPPED;
|
|
}
|
|
//start coordinated txn & join it
|
|
if (CHECK(m_pChgRowset1->StartCoordTxn(&pITransaction,m_fIsoLevel), TRUE))
|
|
{
|
|
//get transactionjoin transaction object.
|
|
if (CHECK(m_pChgRowset1->GetTxnJoin(), S_OK))
|
|
{
|
|
//join MTS
|
|
if (CHECK(m_pChgRowset1->m_pITxnJoin->JoinTransaction ( pITransaction,
|
|
m_fIsoLevel,
|
|
0,
|
|
NULL
|
|
), S_OK))
|
|
{
|
|
m_pChgRowset1->m_fTxnStarted = TRUE;
|
|
|
|
//get a rowset through the command
|
|
m_pChgRowset1->CreateRowsetObject();
|
|
|
|
//Make a change
|
|
if (!COMPARE(Change(m_pChgRowset1), TRUE))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
|
|
//Another command here might or might not work
|
|
//some providers might not allow another command here if the only way to get the command
|
|
//is by implicitly opening another connection because that under-the-covers connection
|
|
//will not be transacted
|
|
//if the command is allowed then that means the second command object is now also enlisted
|
|
//in the transaction
|
|
CHECK(m_pChgRowset1->m_pIDBCreateCommand->CreateCommand(NULL, IID_ICommand, (IUnknown **)&pICommand2),S_OK);
|
|
|
|
//if the second command object is not allowed then skip;
|
|
if (S_OK==hr)
|
|
{
|
|
//create a rowset off the new command and make a change on it
|
|
CHECK((m_pChgRowset1->m_pTable)->Select(NULL,1,IID_IRowsetChange,m_pChgRowset1->m_cPropSets,
|
|
m_pChgRowset1->m_rgPropSets, NULL,(IUnknown **)&pIRowsetChange2,&pICommand2),S_OK);
|
|
//get rowet interface to fetch a row
|
|
|
|
//Get an accessor with all the writeable columns
|
|
CHECK(GetAccessorAndBindings(pIRowsetChange2,
|
|
DBACCESSOR_ROWDATA,
|
|
&hAccessor, &rgBindings, &cBindings, NULL,
|
|
DBPART_VALUE |DBPART_STATUS |DBPART_LENGTH,
|
|
UPDATEABLE_COLS_BOUND, FORWARD, NO_COLS_BY_REF, NULL,
|
|
NULL, NULL, DBTYPE_EMPTY, 0, NULL, NULL,
|
|
NO_COLS_OWNED_BY_PROV, DBPARAMIO_NOTPARAM, BLOB_LONG), S_OK);
|
|
|
|
// Fill buffer with appropriate data for insert of this row number
|
|
CHECK(FillInputBindings(
|
|
m_pChgRowset1->m_pTable,
|
|
DBACCESSOR_ROWDATA,
|
|
cBindings,
|
|
rgBindings,
|
|
(BYTE**)&pData,
|
|
99,
|
|
0,
|
|
NULL),S_OK);
|
|
|
|
CHECK(pIRowsetChange2->InsertRow(NULL, hAccessor, pData, NULL),S_OK);
|
|
|
|
//end the mts coordinated txn, abort it, zombies session
|
|
//this should abort change from both command objects
|
|
// if (CHECK(pITransaction->Abort(NULL, FALSE, FALSE), S_OK))
|
|
if (CHECK(pITransaction->Commit(FALSE, FALSE, FALSE), S_OK))
|
|
{
|
|
g_ulLastActualDelete--;
|
|
g_ulLastActualInsert--;
|
|
//test to see if both command objects are under the global transaction
|
|
//since the CreateCommand passed, if we are here both objects should zombie on the commit
|
|
//so the QI should fail
|
|
// CHECK(VerifyInterface(m_pChgRowset1->m_pIAccessor, IID_IRowsetChange, ROWSET_INTERFACE,(IUnknown **)&pIRowsetChange),E_FAIL);
|
|
// CHECK(VerifyInterface(pICommand2, IID_IRowsetChange, ROWSET_INTERFACE,(IUnknown **)&pIRowsetChange2),E_FAIL);
|
|
fResults = TEST_PASS;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
fResults = TEST_SKIPPED;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
CLEANUP:
|
|
//free objects;
|
|
//Cleanup any out of line memory allocated in FillInputBindings and pData
|
|
|
|
hAccessor = DB_NULL_HACCESSOR;
|
|
SAFE_RELEASE(pICommand2);
|
|
|
|
if(pData)
|
|
{
|
|
ReleaseInputBindingsMemory(cBindings, rgBindings, (BYTE*)pData, TRUE);
|
|
}
|
|
ReleaseAllRowsetsAndTxns();
|
|
SAFE_RELEASE(pIRowsetChange);
|
|
SAFE_RELEASE(pIRowsetChange2);
|
|
m_pChgRowset1->FreeJoinTxn();
|
|
if (pITransaction)
|
|
{
|
|
m_pChgRowset1->FreeCoordTxn(pITransaction);
|
|
pITransaction = NULL;
|
|
}
|
|
return fResults;
|
|
}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(11)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc DBPROP_RESETDATASOURCE
|
|
// this class/variation is purposely put last. DO NOT ADD varaiton after this!
|
|
// this variaiton deletes the table, there will be no more table
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCEnListment::Variation_11()
|
|
{
|
|
BOOL fResults = TEST_SKIPPED;
|
|
HRESULT hr = S_OK;
|
|
ITransaction *pITransaction = NULL;
|
|
IDBInitialize *pIDBInitialize = NULL;
|
|
IDBProperties *pIDBProperties = NULL;
|
|
const ULONG ulProps = 1;
|
|
DBPROP DBProp[ulProps];
|
|
DBPROPSET rgPropSets[1];
|
|
VARIANT_BOOL bValue;
|
|
VARIANT_BOOL bValue2;
|
|
ULONG ulRD = 99;
|
|
ULONG_PTR ulRD2 = 99;
|
|
|
|
//this code may only work if there is one session open so...
|
|
//delete table
|
|
if (m_pThisTestModule->m_pVoid)
|
|
{
|
|
((CTable *)m_pThisTestModule->m_pVoid)->DropTable();
|
|
delete (CTable*)m_pThisTestModule->m_pVoid;
|
|
m_pThisTestModule->m_pVoid = NULL;
|
|
}
|
|
//Clean up encapsulated objects
|
|
ReleaseAllRowsets();
|
|
if (m_pRORowset1)
|
|
{
|
|
m_pRORowset1->Terminate();
|
|
delete m_pRORowset1;
|
|
m_pRORowset1=NULL;
|
|
}
|
|
if (m_pChgRowset2)
|
|
{
|
|
m_pChgRowset2->Terminate();
|
|
delete m_pChgRowset2;
|
|
m_pChgRowset2=NULL;
|
|
}
|
|
|
|
//grab the DSO interface pointers
|
|
if (!VerifyInterface((IUnknown *)m_pThisTestModule->m_pIUnknown, IID_IDBInitialize, DATASOURCE_INTERFACE, (IUnknown**)&pIDBInitialize))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
if (!VerifyInterface(pIDBInitialize, IID_IDBProperties, DATASOURCE_INTERFACE, (IUnknown**)&pIDBProperties))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
|
|
CHECK(GetProperty(DBPROP_RESETDATASOURCE,DBPROPSET_DATASOURCE, (IUnknown *)m_pThisTestModule->m_pIUnknown,&ulRD2),S_OK);
|
|
COMPARE(0,ulRD2);
|
|
|
|
//get the default for DBPROP_MULTIPLECONNECTIONS
|
|
GetProperty(DBPROP_MULTIPLECONNECTIONS,DBPROPSET_DATASOURCE, (IUnknown *)m_pThisTestModule->m_pIUnknown,&bValue);
|
|
|
|
//set 2 dso props cause 2 is more fun than 1
|
|
rgPropSets->rgProperties = &DBProp[0];
|
|
rgPropSets->cProperties = ulProps;
|
|
rgPropSets->guidPropertySet = DBPROPSET_DATASOURCE;
|
|
|
|
//set this prop to the opposite of its default
|
|
if (bValue==VARIANT_TRUE)
|
|
{
|
|
DBProp[0].dwPropertyID = DBPROP_MULTIPLECONNECTIONS;
|
|
DBProp[0].dwOptions = DBPROPOPTIONS_REQUIRED;
|
|
DBProp[0].colid = DB_NULLID;
|
|
DBProp[0].vValue.vt = VT_BOOL;
|
|
V_BOOL(&(DBProp[0].vValue)) = VARIANT_FALSE;
|
|
}
|
|
else
|
|
{
|
|
DBProp[0].dwPropertyID = DBPROP_MULTIPLECONNECTIONS;
|
|
DBProp[0].dwOptions = DBPROPOPTIONS_REQUIRED;
|
|
DBProp[0].colid = DB_NULLID;
|
|
DBProp[0].vValue.vt = VT_BOOL;
|
|
V_BOOL(&(DBProp[0].vValue)) = VARIANT_TRUE;
|
|
}
|
|
|
|
//Set the DBPROP_MULTIPLECONNECTIONS to opposite of the default
|
|
hr = pIDBProperties->SetProperties(1, rgPropSets);
|
|
//make sure were ok here
|
|
GetProperty(DBPROP_MULTIPLECONNECTIONS,DBPROPSET_DATASOURCE, (IUnknown *)m_pThisTestModule->m_pIUnknown,&bValue2);
|
|
|
|
if (DB_E_ERRORSOCCURRED == hr)
|
|
{
|
|
//if this prop can not be set, pretend like it passed so the test goes on
|
|
if (bValue2==VARIANT_TRUE)
|
|
{
|
|
bValue2=VARIANT_FALSE;
|
|
}
|
|
else
|
|
{
|
|
bValue2=VARIANT_TRUE;
|
|
}
|
|
}
|
|
|
|
//if the set failed, something is wrong so end here
|
|
if (S_OK != hr)
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
|
|
//if the prop was not set the test changes the 2nd of these
|
|
//if the prop was set then the 2nd of these was changed by the provider
|
|
if (bValue==bValue2)
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
|
|
fResults = TEST_FAIL;
|
|
|
|
//set DBPROP_RESETDATASOURCE to re-initialize the DSO
|
|
DBProp[0].dwPropertyID = DBPROP_RESETDATASOURCE;
|
|
DBProp[0].dwOptions = DBPROPOPTIONS_REQUIRED;
|
|
DBProp[0].colid = DB_NULLID;
|
|
DBProp[0].vValue.vt = VT_I4;
|
|
DBProp[0].vValue.lVal = DBPROPVAL_RD_RESETALL;
|
|
|
|
//start coordinated txn & join it
|
|
if (CHECK(m_pChgRowset1->StartCoordTxn(&pITransaction,m_fIsoLevel), TRUE))
|
|
{
|
|
//get transactionjoin transaction object.
|
|
if (CHECK(m_pChgRowset1->GetTxnJoin(), S_OK))
|
|
{
|
|
//join MTS
|
|
TESTC_(m_pChgRowset1->m_pITxnJoin->JoinTransaction ( pITransaction,
|
|
m_fIsoLevel,
|
|
0,
|
|
NULL
|
|
), S_OK);
|
|
m_pChgRowset1->m_fTxnStarted = TRUE;
|
|
|
|
//Set the DBPROP_RESETDATASOURCE to reset all
|
|
CHECK(pIDBProperties->SetProperties(1, rgPropSets),S_OK);
|
|
|
|
//DSO should still be initialized
|
|
CHECK(pIDBInitialize->Initialize(),DB_E_ALREADYINITIALIZED);
|
|
|
|
//make sure session is still in dtc/txn
|
|
if (!CHECK(m_pChgRowset1->AbortCoord(FALSE, pITransaction,m_pChgRowset1->m_pITxnJoin), S_OK))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
|
|
//get the value for DBPROP_MULTIPLECONNECTIONS again
|
|
GetProperty(DBPROP_MULTIPLECONNECTIONS,DBPROPSET_DATASOURCE, (IUnknown *)m_pThisTestModule->m_pIUnknown,&bValue2);
|
|
|
|
//this should be the default now
|
|
COMPARE(bValue,bValue2);
|
|
|
|
//open a rowset w/new props
|
|
m_pChgRowset1->CreateRowsetObject();
|
|
|
|
//Setting DBPROP_RESETDATASOURCE with an open rowset should fail
|
|
TESTC_(pIDBProperties->SetProperties(1, rgPropSets),DB_E_ERRORSOCCURRED);
|
|
if (rgPropSets->rgProperties->dwStatus!=DBPROPSTATUS_NOTSET &&
|
|
rgPropSets->rgProperties->dwStatus!=DBPROPSTATUS_NOTSETTABLE)
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
|
|
//clean up any open objects
|
|
m_pChgRowset1->ReleaseRowsetObject();
|
|
|
|
//add setting multiple DSO props w/RESETDATASOURCE here once 42987 is resloved
|
|
|
|
fResults = TEST_PASS;
|
|
}
|
|
}
|
|
CLEANUP:
|
|
//free objects;
|
|
// ReleaseAllRowsetsAndTxns();
|
|
m_pChgRowset1->FreeJoinTxn();
|
|
if (pITransaction)
|
|
{
|
|
m_pChgRowset1->FreeCoordTxn(pITransaction);
|
|
pITransaction = NULL;
|
|
}
|
|
SAFE_RELEASE(pIDBInitialize);
|
|
SAFE_RELEASE(pIDBProperties);
|
|
return fResults;
|
|
}
|
|
// }}
|
|
|
|
|
|
BOOL TCEnListment::Terminate()
|
|
{
|
|
// {{ TCW_TERM_BASECLASS_CHECK2
|
|
return(CTxnImmed::Terminate());
|
|
} // }}
|
|
// }}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_TC_PROTOTYPE(TCRetainPreserve)
|
|
//*-----------------------------------------------------------------------
|
|
//| Test Case: TCRetainPreserve - Retaining/Preserving Behavior
|
|
//| Created: 04/16/96
|
|
//*-----------------------------------------------------------------------
|
|
|
|
//--------------------------------------------------------------------
|
|
// @mfunc TestCase Initialization Routine
|
|
//
|
|
// @rdesc TRUE or FALSE
|
|
//
|
|
BOOL TCRetainPreserve::Init()
|
|
{
|
|
// {{ TCW_INIT_BASECLASS_CHECK
|
|
if(CTxnImmed::Init())
|
|
// }}
|
|
{
|
|
//the jet engine (access) does not support distributed transactions
|
|
if (m_fOnAccess)
|
|
{
|
|
return TEST_SKIPPED;
|
|
}
|
|
else
|
|
{
|
|
return TEST_PASS;
|
|
}
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
//--------------------------------------------------------------------
|
|
// @mfunc Tests retaining semantics for a specific isolation level
|
|
//
|
|
// @rdesc TRUE or FALSE
|
|
//
|
|
BOOL TCRetainPreserve::CommitRetain(ISOLEVEL fIsoLevel)
|
|
{
|
|
BOOL fResults = FALSE;
|
|
HACCESSOR hAccessor = DB_NULL_HACCESSOR;
|
|
HROW hRow = DB_NULL_HROW;
|
|
HRESULT hr;
|
|
ITransaction *pITransaction = NULL;
|
|
|
|
//start coordinated txn & join it
|
|
if (CHECK(m_pChgRowset1->StartCoordTxn(&pITransaction,fIsoLevel), TRUE))
|
|
{
|
|
//get transactionjoin transaction object.
|
|
if (CHECK(m_pChgRowset1->GetTxnJoin(), S_OK))
|
|
{
|
|
if (CHECK(m_pChgRowset1->m_pITxnJoin->JoinTransaction ( pITransaction,
|
|
fIsoLevel,
|
|
0,
|
|
NULL
|
|
), S_OK))
|
|
{
|
|
m_pChgRowset1->m_fTxnStarted = TRUE;
|
|
|
|
hr=m_pChgRowset1->MakeRowset();
|
|
if (!(hr==S_OK||hr==DB_S_ERRORSOCCURRED))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
|
|
//if provider does not support IRowsetChange
|
|
if (!m_pChgRowset1->m_fChange)
|
|
{
|
|
if(!CHECK((m_pChgRowset1->m_pTable)->Insert(GetNextRowToInsert()), S_OK))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//Do something in txn
|
|
if(!COMPARE(Insert(m_pChgRowset1), TRUE))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
}
|
|
|
|
//Now commit it with retaining TRUE. this should fail, dtc does not support retaining
|
|
if (!CHECK(m_hr = pITransaction->Commit(TRUE, FALSE, FALSE), XACT_E_CANTRETAIN))
|
|
{
|
|
m_pChgRowset1->m_fTxnStarted = FALSE;
|
|
if (S_OK==m_hr)
|
|
{
|
|
//Our last insert was mistakenly committed, so increment row count
|
|
m_pChgRowset1->m_fTxnPendingInsert = FALSE;
|
|
g_InsertIncrement();
|
|
}
|
|
fResults=FALSE;
|
|
goto CLEANUP;
|
|
}
|
|
|
|
//Make sure the Txn Info is correct
|
|
// Because transaction did not start so no need to check this.
|
|
//VerifyTxnInfo(pITransaction, m_fIsoLevel);
|
|
|
|
fResults = TRUE;
|
|
}
|
|
}
|
|
}
|
|
CLEANUP:
|
|
ReleaseAllRowsetsAndTxns();
|
|
|
|
if ((hAccessor != DB_NULL_HACCESSOR) && m_pChgRowset1->m_pIAccessor)
|
|
CHECK(m_pChgRowset1->m_pIAccessor->ReleaseAccessor(hAccessor, NULL), S_OK);
|
|
|
|
//free objects;
|
|
m_pChgRowset1->FreeJoinTxn();
|
|
if (pITransaction)
|
|
{
|
|
m_pChgRowset1->FreeCoordTxn(pITransaction);
|
|
pITransaction = NULL;
|
|
}
|
|
|
|
return fResults;
|
|
}
|
|
|
|
//--------------------------------------------------------------------
|
|
// @mfunc Tests retaining semantics for a specific isolation level
|
|
//
|
|
// @rdesc TRUE or FALSE
|
|
//
|
|
BOOL TCRetainPreserve::CommitNonRetain(ISOLEVEL fIsoLevel)
|
|
{
|
|
BOOL fResults = FALSE;
|
|
HACCESSOR hAccessor = DB_NULL_HACCESSOR;
|
|
HROW hRow = DB_NULL_HROW;
|
|
HRESULT hr = S_OK;
|
|
ITransaction *pITransaction = NULL;
|
|
|
|
|
|
//start coordinated txn & join it
|
|
if (CHECK(m_pChgRowset1->StartCoordTxn(&pITransaction,fIsoLevel), TRUE))
|
|
{
|
|
//get transactionjoin transaction object.
|
|
if (CHECK(m_pChgRowset1->GetTxnJoin(), S_OK))
|
|
{
|
|
if (CHECK(m_pChgRowset1->m_pITxnJoin->JoinTransaction ( pITransaction,
|
|
fIsoLevel,
|
|
0,
|
|
NULL
|
|
), S_OK))
|
|
{
|
|
m_pChgRowset1->m_fTxnStarted = TRUE;
|
|
|
|
hr=m_pChgRowset1->MakeRowset();
|
|
if (!(hr==S_OK||hr==DB_S_ERRORSOCCURRED))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
|
|
//if provider does not support IRowsetChange
|
|
if (!m_pChgRowset1->m_fChange)
|
|
{
|
|
if(!CHECK((m_pChgRowset1->m_pTable)->Insert(GetNextRowToInsert()), S_OK))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//Do something in txn
|
|
if(!COMPARE(Insert(m_pChgRowset1), TRUE))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
}
|
|
//Sleep for a few seconds; this is to ensure that the back end has had
|
|
//time to make this update visible to other transactions which
|
|
//should see it. This is only necessary for Access, which only does
|
|
//this every few seconds.
|
|
if (m_fOnAccess)
|
|
{
|
|
Sleep(SLEEP_TIME); //Takes milliseconds as param
|
|
}
|
|
|
|
//Now commit it
|
|
if (CHECK(pITransaction->Commit(FALSE, FALSE, FALSE), S_OK))
|
|
{
|
|
m_pChgRowset1->m_fTxnStarted = FALSE;
|
|
//Our last insert was mistakenly committed, so increment row count
|
|
m_pChgRowset1->m_fTxnPendingInsert = FALSE;
|
|
g_InsertIncrement();
|
|
fResults = TRUE;
|
|
}
|
|
else
|
|
{
|
|
//commit failed, no row inserted
|
|
g_ulLastActualInsert--;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
CLEANUP:
|
|
ReleaseAllRowsetsAndTxns();
|
|
|
|
if ((hAccessor != DB_NULL_HACCESSOR) && m_pChgRowset1->m_pIAccessor)
|
|
CHECK(m_pChgRowset1->m_pIAccessor->ReleaseAccessor(hAccessor, NULL), S_OK);
|
|
|
|
//free objects;
|
|
m_pChgRowset1->FreeJoinTxn();
|
|
if (pITransaction)
|
|
{
|
|
m_pChgRowset1->FreeCoordTxn(pITransaction);
|
|
pITransaction = NULL;
|
|
}
|
|
|
|
return fResults;
|
|
}
|
|
|
|
|
|
//--------------------------------------------------------------------
|
|
// @mfunc Tests retaining semantics for a specific isolation level
|
|
//
|
|
// @rdesc TRUE or FALSE
|
|
//
|
|
BOOL TCRetainPreserve::AbortRetain(ISOLEVEL fIsoLevel)
|
|
{
|
|
BOOL fResults = FALSE;
|
|
HACCESSOR hAccessor = DB_NULL_HACCESSOR;
|
|
HROW hRow = DB_NULL_HROW;
|
|
HRESULT hr;
|
|
ITransaction *pITransaction = NULL;
|
|
|
|
//start coordinated txn & join it
|
|
if (CHECK(m_pChgRowset1->StartCoordTxn(&pITransaction,fIsoLevel), TRUE))
|
|
{
|
|
//get transactionjoin transaction object.
|
|
if (CHECK(m_pChgRowset1->GetTxnJoin(), S_OK))
|
|
{
|
|
if (CHECK(m_pChgRowset1->m_pITxnJoin->JoinTransaction ( pITransaction,
|
|
fIsoLevel,
|
|
0,
|
|
NULL
|
|
), S_OK))
|
|
{
|
|
m_pChgRowset1->m_fTxnStarted = TRUE;
|
|
|
|
hr=m_pChgRowset1->MakeRowset();
|
|
if (!(hr==S_OK||hr==DB_S_ERRORSOCCURRED))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
|
|
//if provider does not support IRowsetChange
|
|
if (!m_pChgRowset1->m_fChange)
|
|
{
|
|
if(!CHECK((m_pChgRowset1->m_pTable)->Insert(GetNextRowToInsert()), S_OK))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//Do something in txn
|
|
if(!COMPARE(Insert(m_pChgRowset1), TRUE))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
}
|
|
|
|
//Now abort it with retaining TRUE. this should fail, dtc does not support retaining
|
|
if (!CHECK(m_hr = pITransaction->Abort(NULL, FALSE, FALSE), XACT_E_CANTRETAIN))
|
|
{
|
|
m_pChgRowset1->m_fTxnStarted = FALSE;
|
|
if (S_OK==m_hr)
|
|
{
|
|
//Our last insert was mistakenly committed, so increment row count
|
|
m_pChgRowset1->m_fTxnPendingInsert = FALSE;
|
|
}
|
|
fResults=FALSE;
|
|
goto CLEANUP;
|
|
}
|
|
|
|
//Make sure the Txn Info is correct
|
|
VerifyTxnInfo(pITransaction, m_fIsoLevel);
|
|
|
|
fResults = TRUE;
|
|
}
|
|
}
|
|
}
|
|
CLEANUP:
|
|
ReleaseAllRowsetsAndTxns();
|
|
|
|
if ((hAccessor != DB_NULL_HACCESSOR) && m_pChgRowset1->m_pIAccessor)
|
|
CHECK(m_pChgRowset1->m_pIAccessor->ReleaseAccessor(hAccessor, NULL), S_OK);
|
|
//free objects;
|
|
m_pChgRowset1->FreeJoinTxn();
|
|
if (pITransaction)
|
|
{
|
|
m_pChgRowset1->FreeCoordTxn(pITransaction);
|
|
pITransaction = NULL;
|
|
}
|
|
return fResults;
|
|
}
|
|
|
|
|
|
//--------------------------------------------------------------------
|
|
// @mfunc Tests retaining semantics for a specific isolation level
|
|
//
|
|
// @rdesc TRUE or FALSE
|
|
//
|
|
BOOL TCRetainPreserve::AbortNonRetain(ISOLEVEL fIsoLevel)
|
|
{
|
|
BOOL fResults = FALSE;
|
|
HACCESSOR hAccessor = DB_NULL_HACCESSOR;
|
|
HROW hRow = DB_NULL_HROW;
|
|
HRESULT hr;
|
|
ITransaction *pITransaction = NULL;
|
|
|
|
//start coordinated txn & join it
|
|
if (CHECK(m_pChgRowset1->StartCoordTxn(&pITransaction,fIsoLevel), TRUE))
|
|
{
|
|
//get transactionjoin transaction object.
|
|
if (CHECK(m_pChgRowset1->GetTxnJoin(), S_OK))
|
|
{
|
|
if (CHECK(m_pChgRowset1->m_pITxnJoin->JoinTransaction ( pITransaction,
|
|
fIsoLevel,
|
|
0,
|
|
NULL
|
|
), S_OK))
|
|
{
|
|
m_pChgRowset1->m_fTxnStarted = TRUE;
|
|
|
|
hr=m_pChgRowset1->MakeRowset();
|
|
if (!(hr==S_OK||hr==DB_S_ERRORSOCCURRED))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
|
|
//if provider does not support IRowsetChange
|
|
if (!m_pChgRowset1->m_fChange)
|
|
{
|
|
if(!CHECK((m_pChgRowset1->m_pTable)->Insert(GetNextRowToInsert()), S_OK))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//Do something in txn
|
|
if(!COMPARE(Insert(m_pChgRowset1), TRUE))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
}
|
|
//Sleep for a few seconds; this is to ensure that the back end has had
|
|
//time to make this update visible to other transactions which
|
|
//should see it. This is only necessary for Access, which only does
|
|
//this every few seconds.
|
|
if (m_fOnAccess)
|
|
{
|
|
Sleep(SLEEP_TIME); //Takes milliseconds as param
|
|
}
|
|
|
|
//Make sure the Txn Info is correct
|
|
VerifyTxnInfo(pITransaction, fIsoLevel);
|
|
|
|
//Now abort it
|
|
if (CHECK(pITransaction->Abort(NULL, FALSE, FALSE), S_OK))
|
|
{
|
|
//Our last insert was just aborted, so it's no longer pending
|
|
m_pChgRowset1->m_fTxnStarted = FALSE;
|
|
m_pChgRowset1->m_fTxnPendingInsert = FALSE;
|
|
fResults = TRUE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
CLEANUP:
|
|
ReleaseAllRowsetsAndTxns();
|
|
|
|
if ((hAccessor != DB_NULL_HACCESSOR) && m_pChgRowset1->m_pIAccessor)
|
|
CHECK(m_pChgRowset1->m_pIAccessor->ReleaseAccessor(hAccessor, NULL), S_OK);
|
|
//free objects;
|
|
m_pChgRowset1->FreeJoinTxn();
|
|
if (pITransaction)
|
|
{
|
|
m_pChgRowset1->FreeCoordTxn(pITransaction);
|
|
pITransaction = NULL;
|
|
}
|
|
|
|
return fResults;
|
|
}
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(1)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc Commit(fRetaining = TRUE
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCRetainPreserve::Variation_1()
|
|
{
|
|
IDBInitialize *pIDBInitialize = NULL;
|
|
int nResult = TEST_FAIL;
|
|
ULONG_PTR ulSupportedIso = 0,
|
|
i;
|
|
|
|
// Get IDBInitialize interface
|
|
TESTC(VerifyInterface((IUnknown *)m_pThisTestModule->m_pIUnknown, IID_IDBInitialize, DATASOURCE_INTERFACE, (IUnknown**)&pIDBInitialize));
|
|
|
|
// Determine if this is a supported property
|
|
TESTC_PROVIDER(SupportedProperty(DBPROP_SUPPORTEDTXNISOLEVELS, DBPROPSET_DATASOURCEINFO, pIDBInitialize));
|
|
|
|
// Now get the property
|
|
TESTC(GetProperty(DBPROP_SUPPORTEDTXNISOLEVELS, DBPROPSET_DATASOURCEINFO, pIDBInitialize, &ulSupportedIso));
|
|
|
|
for(i=0; i<g_ulTotalIsolations; i++) {
|
|
odtLog << g_IsolationList[i].pszDesc;
|
|
|
|
if ((g_IsolationList[i].ulIsolation & ulSupportedIso) == g_IsolationList[i].ulIsolation) {
|
|
odtLog << "\n";
|
|
CHECK(CommitRetain(g_IsolationList[i].ulIsolation), true);
|
|
}
|
|
else
|
|
odtLog << "\t-> Not Supported\n";
|
|
}
|
|
|
|
nResult = TEST_PASS;
|
|
|
|
CLEANUP:
|
|
SAFE_RELEASE(pIDBInitialize);
|
|
|
|
return nResult;
|
|
}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(2)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc Commit(fRetaining = FALSE
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCRetainPreserve::Variation_2()
|
|
{
|
|
IDBInitialize *pIDBInitialize = NULL;
|
|
int nResult = TEST_FAIL;
|
|
ULONG_PTR ulSupportedIso = 0,
|
|
i;
|
|
|
|
// Get IDBInitialize interface
|
|
TESTC(VerifyInterface((IUnknown *)m_pThisTestModule->m_pIUnknown, IID_IDBInitialize, DATASOURCE_INTERFACE, (IUnknown**)&pIDBInitialize));
|
|
|
|
// Determine if this is a supported property
|
|
TESTC_PROVIDER(SupportedProperty(DBPROP_SUPPORTEDTXNISOLEVELS, DBPROPSET_DATASOURCEINFO, pIDBInitialize));
|
|
|
|
// Now get the property
|
|
TESTC(GetProperty(DBPROP_SUPPORTEDTXNISOLEVELS, DBPROPSET_DATASOURCEINFO, pIDBInitialize, &ulSupportedIso));
|
|
|
|
for(i=0; i<g_ulTotalIsolations; i++) {
|
|
odtLog << g_IsolationList[i].pszDesc;
|
|
|
|
if ((g_IsolationList[i].ulIsolation & ulSupportedIso) == g_IsolationList[i].ulIsolation) {
|
|
odtLog << "\n";
|
|
CHECK(CommitNonRetain(g_IsolationList[i].ulIsolation), true);
|
|
}
|
|
else
|
|
odtLog << "\t-> Not Supported\n";
|
|
}
|
|
|
|
nResult = TEST_PASS;
|
|
|
|
CLEANUP:
|
|
SAFE_RELEASE(pIDBInitialize);
|
|
|
|
return nResult;
|
|
}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(3)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc Abort(fRetaining = TRUE
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCRetainPreserve::Variation_3()
|
|
{
|
|
IDBInitialize *pIDBInitialize = NULL;
|
|
int nResult = TEST_FAIL;
|
|
ULONG_PTR ulSupportedIso = 0,
|
|
i;
|
|
|
|
// Get IDBInitialize interface
|
|
TESTC(VerifyInterface((IUnknown *)m_pThisTestModule->m_pIUnknown, IID_IDBInitialize, DATASOURCE_INTERFACE, (IUnknown**)&pIDBInitialize));
|
|
|
|
// Determine if this is a supported property
|
|
TESTC_PROVIDER(SupportedProperty(DBPROP_SUPPORTEDTXNISOLEVELS, DBPROPSET_DATASOURCEINFO, pIDBInitialize));
|
|
|
|
// Now get the property
|
|
TESTC(GetProperty(DBPROP_SUPPORTEDTXNISOLEVELS, DBPROPSET_DATASOURCEINFO, pIDBInitialize, &ulSupportedIso));
|
|
|
|
for(i=0; i<g_ulTotalIsolations; i++) {
|
|
odtLog << g_IsolationList[i].pszDesc;
|
|
|
|
if ((g_IsolationList[i].ulIsolation & ulSupportedIso) == g_IsolationList[i].ulIsolation) {
|
|
odtLog << "\n";
|
|
CHECK(AbortRetain(g_IsolationList[i].ulIsolation), true);
|
|
}
|
|
else
|
|
odtLog << "\t-> Not Supported\n";
|
|
}
|
|
|
|
nResult = TEST_PASS;
|
|
|
|
CLEANUP:
|
|
SAFE_RELEASE(pIDBInitialize);
|
|
|
|
return nResult;
|
|
}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(4)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc Abort(fRetaining = FALSE
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCRetainPreserve::Variation_4()
|
|
{
|
|
IDBInitialize *pIDBInitialize = NULL;
|
|
int nResult = TEST_FAIL;
|
|
ULONG_PTR ulSupportedIso = 0,
|
|
i;
|
|
|
|
// Get IDBInitialize interface
|
|
TESTC(VerifyInterface((IUnknown *)m_pThisTestModule->m_pIUnknown, IID_IDBInitialize, DATASOURCE_INTERFACE, (IUnknown**)&pIDBInitialize));
|
|
|
|
// Determine if this is a supported property
|
|
TESTC_PROVIDER(SupportedProperty(DBPROP_SUPPORTEDTXNISOLEVELS, DBPROPSET_DATASOURCEINFO, pIDBInitialize));
|
|
|
|
// Now get the property
|
|
TESTC(GetProperty(DBPROP_SUPPORTEDTXNISOLEVELS, DBPROPSET_DATASOURCEINFO, pIDBInitialize, &ulSupportedIso));
|
|
|
|
for(i=0; i<g_ulTotalIsolations; i++) {
|
|
odtLog << g_IsolationList[i].pszDesc;
|
|
|
|
if ((g_IsolationList[i].ulIsolation & ulSupportedIso) == g_IsolationList[i].ulIsolation) {
|
|
odtLog << "\n";
|
|
CHECK(AbortNonRetain(g_IsolationList[i].ulIsolation), true);
|
|
}
|
|
else
|
|
odtLog << "\t-> Not Supported\n";
|
|
}
|
|
|
|
nResult = TEST_PASS;
|
|
|
|
CLEANUP:
|
|
SAFE_RELEASE(pIDBInitialize);
|
|
|
|
return nResult;
|
|
}
|
|
|
|
// }}
|
|
// {{ TCW_TERMINATE_METHOD
|
|
//--------------------------------------------------------------------
|
|
// @mfunc TestCase Termination Routine
|
|
//
|
|
// @rdesc TRUE or FALSE
|
|
//
|
|
BOOL TCRetainPreserve::Terminate()
|
|
{
|
|
// TO DO: Add your own code here
|
|
|
|
// {{ TCW_TERM_BASECLASS_CHECK2
|
|
return(CTxnImmed::Terminate());
|
|
} // }}
|
|
// }}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_TC_PROTOTYPE(TCIRowsetUpdate)
|
|
//*-----------------------------------------------------------------------
|
|
//| Test Case: TCIRowsetUpdate - Transacted rowsets in Buffered Update mode
|
|
//| Created: 05/06/96
|
|
//*-----------------------------------------------------------------------
|
|
|
|
//--------------------------------------------------------------------
|
|
// @mfunc TestCase Initialization Routine
|
|
//
|
|
// @rdesc TRUE or FALSE
|
|
//
|
|
BOOL TCIRowsetUpdate::Init()
|
|
{
|
|
// {{ TCW_INIT_BASECLASS_CHECK
|
|
if(CTxnUpdate::Init())
|
|
// }}
|
|
{
|
|
//the jet engine (access) does not support distributed transactions
|
|
if (m_fOnAccess)
|
|
{
|
|
return TEST_SKIPPED;
|
|
}
|
|
else
|
|
{
|
|
return TEST_PASS;
|
|
}
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(1)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc Change, Abort with fRetaining = FALSE, Update
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCIRowsetUpdate::Variation_1()
|
|
{
|
|
BOOL fResults = FALSE;
|
|
HRESULT hr;
|
|
ITransaction *pITransaction = NULL;
|
|
HRESULT hExpectedHR;
|
|
DBCOUNTITEM cRows = 0;
|
|
DBROWSTATUS *prgRowStatus = NULL;
|
|
HROW *pHRows = NULL;
|
|
//if provider does not support IRowsetChange
|
|
if (!m_pChgUpdRowset1->m_fChange)
|
|
{
|
|
odtLog << L"IRowsetChange not supported" << wszNewLine;
|
|
fResults = TRUE;
|
|
goto CLEANUP;
|
|
}
|
|
|
|
//start coordinated txn & join it
|
|
if (CHECK(m_pChgUpdRowset1->StartCoordTxn(&pITransaction,m_fIsoLevel), TRUE))
|
|
{
|
|
//get transactionjoin transaction object.
|
|
if (CHECK(m_pChgUpdRowset1->GetTxnJoin(), S_OK))
|
|
{
|
|
if (CHECK(m_pChgUpdRowset1->m_pITxnJoin->JoinTransaction ( pITransaction,
|
|
m_fIsoLevel,
|
|
0,
|
|
NULL
|
|
), S_OK))
|
|
{
|
|
m_pChgUpdRowset1->m_fTxnStarted = TRUE;
|
|
|
|
hr=m_pChgUpdRowset1->MakeRowset();
|
|
if (!(hr==S_OK||hr==DB_S_ERRORSOCCURRED))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
|
|
//Make a change
|
|
if (!COMPARE(Change(m_pChgUpdRowset1), TRUE))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
|
|
//Abort txn, change was pending but the rowset is zombied so it's not anymore
|
|
if (!CHECK(m_pChgUpdRowset1->AbortCoord(FALSE, pITransaction,m_pChgUpdRowset1->m_pITxnJoin), S_OK))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
|
|
m_pChgUpdRowset1->m_fTxnStarted = FALSE;
|
|
|
|
//Verify pending row (or lack thereof)
|
|
if (!m_pChgUpdRowset1->CheckPendingRow(1))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
|
|
//Use second rowset to verify we can't see the change
|
|
if (!COMPARE(FindChange(m_pChgUpdRowset2), FALSE))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
|
|
//delete second rowset in case it will be used again in this variation
|
|
if (!CHECK(m_pChgUpdRowset2->FreeRowset(), S_OK))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
|
|
//the following is commented out because preserve does not apply to distributed txns
|
|
//it has yet to be decided whether sessions will be preserved at commit/abort
|
|
//until then it is provider specific where the session is preserved or not with no way to determine this before doing it
|
|
// if (m_pChgUpdRowset1->m_fAbortPreserve)
|
|
// {
|
|
hExpectedHR = S_OK;
|
|
// }
|
|
// else
|
|
// {
|
|
// hExpectedHR = E_UNEXPECTED;
|
|
// }
|
|
|
|
//Call update for all pending changes
|
|
|
|
//if the session zombied then this should return and error
|
|
//if the session didn't zombie then this is ok and change goto back end (autocommit mode at this point)
|
|
if (!CHECK(m_pChgUpdRowset1->m_pIRowsetUpdate->Update( NULL,
|
|
0,
|
|
NULL,
|
|
&cRows,
|
|
&pHRows,
|
|
&prgRowStatus), hExpectedHR))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
|
|
//if this commits and then Updates the pending rows look like a delete then
|
|
//insert as far as the back end data is concerened
|
|
g_ulLastActualInsert++;
|
|
g_ulLastActualDelete++;
|
|
|
|
//Commit the update (no matter if it succedded or not)
|
|
//shouldn't work, retaining is FALSE, there is no current transaction
|
|
if (!CHECK(m_pChgUpdRowset1->CommitCoord(FALSE, pITransaction,m_pChgUpdRowset1->m_pITxnJoin), XACT_E_NOTRANSACTION))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
if (!CHECK(m_pChgUpdRowset1->AbortCoord(FALSE, pITransaction,m_pChgUpdRowset1->m_pITxnJoin), XACT_E_NOTRANSACTION))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
|
|
//Sleep for a few seconds; this is to ensure that the back end has had
|
|
//time to make this update visible to other transactions which
|
|
//should see it. This is only necessary for Access, which only does
|
|
//this every few seconds.
|
|
if (m_fOnAccess)
|
|
Sleep(SLEEP_TIME); //Takes milliseconds as param
|
|
|
|
//the following is commented out because preserve does not apply to distributed txns
|
|
//it has yet to be decided whether sessions will be preserved at commit/abort
|
|
//until then it is provider specific where the session is preserved or not with no way to determine this before doing it
|
|
// if (m_pChgUpdRowset1->m_fAbortPreserve)
|
|
// {
|
|
// //We should now be able to see the change (if we are here Update should have worked)
|
|
//since we updated and our change from before the abort should have been
|
|
//preserved
|
|
if (!COMPARE(FindChange(m_pChgUpdRowset2), TRUE))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
// }
|
|
// else
|
|
// {
|
|
// //We shouldn't see a change because the rowset
|
|
// //should have zomibied on abort, losing the pending change
|
|
// if (!COMPARE(FindChange(m_pChgUpdRowset2), FALSE))
|
|
// {
|
|
// goto CLEANUP;
|
|
// }
|
|
// }
|
|
}
|
|
}
|
|
}
|
|
//Everything went OK
|
|
fResults = TRUE;
|
|
CLEANUP:
|
|
if(pHRows)
|
|
{
|
|
CHECK(m_pChgUpdRowset1->m_pIRowset->ReleaseRows(cRows,pHRows,NULL,NULL,NULL),S_OK);
|
|
}
|
|
|
|
CHECK(m_pChgUpdRowset1->FreeRowset(), S_OK);
|
|
CHECK(m_pChgUpdRowset2->FreeRowset(), S_OK);
|
|
|
|
//free objects;
|
|
m_pChgUpdRowset1->FreeJoinTxn();
|
|
if (pITransaction)
|
|
{
|
|
m_pChgUpdRowset1->FreeCoordTxn(pITransaction);
|
|
pITransaction = NULL;
|
|
}
|
|
m_pChgUpdRowset2->FreeJoinTxn();
|
|
if (pITransaction)
|
|
{
|
|
m_pChgUpdRowset2->FreeCoordTxn(pITransaction);
|
|
pITransaction = NULL;
|
|
}
|
|
|
|
PROVIDER_FREE(pHRows);
|
|
|
|
PROVIDER_FREE(prgRowStatus);
|
|
ReleaseAllRowsetsAndTxns();
|
|
|
|
if (fResults)
|
|
return TEST_PASS;
|
|
else
|
|
return TEST_FAIL;
|
|
}
|
|
// }}
|
|
// {{ TCW_VAR_PROTOTYPE(2)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc Change, Update, Abort with fRetaining = FALSE
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCIRowsetUpdate::Variation_2()
|
|
{
|
|
BOOL fResults = FALSE;
|
|
HRESULT hr;
|
|
ITransaction *pITransaction = NULL;
|
|
|
|
//if provider does not support IRowsetChange
|
|
if (!m_pChgUpdRowset1->m_fChange)
|
|
{
|
|
odtLog << L"IRowsetChange not supported" << wszNewLine;
|
|
fResults = TRUE;
|
|
goto CLEANUP;
|
|
}
|
|
|
|
//start coordinated txn & join it
|
|
if (CHECK(m_pChgUpdRowset1->StartCoordTxn(&pITransaction,m_fIsoLevel), TRUE))
|
|
{
|
|
//get transactionjoin transaction object.
|
|
if (CHECK(m_pChgUpdRowset1->GetTxnJoin(), S_OK))
|
|
{
|
|
if (CHECK(m_pChgUpdRowset1->m_pITxnJoin->JoinTransaction ( pITransaction,
|
|
m_fIsoLevel,
|
|
0,
|
|
NULL
|
|
), S_OK))
|
|
{
|
|
m_pChgUpdRowset1->m_fTxnStarted = TRUE;
|
|
|
|
hr=m_pChgUpdRowset1->MakeRowset();
|
|
if (!(hr==S_OK||hr==DB_S_ERRORSOCCURRED))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
//Make a change
|
|
if (!COMPARE(Change(m_pChgUpdRowset1), TRUE))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
|
|
if (!CHECK(m_pChgUpdRowset1->m_pIRowsetUpdate->Update( NULL,
|
|
0,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL), S_OK))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
|
|
//Abort the change, with fRetaining = FALSE
|
|
if (!CHECK(m_pChgUpdRowset1->AbortCoord(FALSE, pITransaction,m_pChgUpdRowset1->m_pITxnJoin), S_OK))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
m_pChgUpdRowset1->m_fTxnStarted = FALSE;
|
|
|
|
//Sleep for a few seconds; this is to ensure that the back end has had
|
|
//time to make this update visible to other transactions which
|
|
//should see it. This is only necessary for Access, which only does
|
|
//this every few seconds.
|
|
if (m_fOnAccess)
|
|
Sleep(SLEEP_TIME); //Takes milliseconds as param
|
|
|
|
//Verify no pending row (or lack thereof) after the abort
|
|
//since we already called update
|
|
if (!m_pChgUpdRowset1->CheckPendingRow(0))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
|
|
//Use second rowset to verify we can't see the change
|
|
if (!COMPARE(FindChange(m_pChgUpdRowset2), FALSE))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
//Everything went OK
|
|
fResults = TRUE;
|
|
CLEANUP:
|
|
CHECK(m_pChgUpdRowset1->FreeRowset(), S_OK);
|
|
CHECK(m_pChgUpdRowset2->FreeRowset(), S_OK);
|
|
|
|
//free objects;
|
|
m_pChgUpdRowset1->FreeJoinTxn();
|
|
if (pITransaction)
|
|
{
|
|
m_pChgUpdRowset1->FreeCoordTxn(pITransaction);
|
|
pITransaction = NULL;
|
|
}
|
|
m_pChgUpdRowset2->FreeJoinTxn();
|
|
if (pITransaction)
|
|
{
|
|
m_pChgUpdRowset2->FreeCoordTxn(pITransaction);
|
|
pITransaction = NULL;
|
|
}
|
|
ReleaseAllRowsetsAndTxns();
|
|
|
|
if (fResults)
|
|
return TEST_PASS;
|
|
else
|
|
return TEST_FAIL;
|
|
}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(3)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc Change, Commit with fRetaining = FALSE, Update
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCIRowsetUpdate::Variation_3()
|
|
{
|
|
BOOL fResults = FALSE;
|
|
HRESULT hr;
|
|
ITransaction *pITransaction = NULL;
|
|
HRESULT hExpectedHR;
|
|
|
|
//if provider does not support IRowsetChange
|
|
if (!m_pChgUpdRowset1->m_fChange)
|
|
{
|
|
odtLog << L"IRowsetChange not supported" << wszNewLine;
|
|
fResults = TRUE;
|
|
goto CLEANUP;
|
|
}
|
|
|
|
//start coordinated txn & join it
|
|
if (CHECK(m_pChgUpdRowset1->StartCoordTxn(&pITransaction,m_fIsoLevel), TRUE))
|
|
{
|
|
//get transactionjoin transaction object.
|
|
if (CHECK(m_pChgUpdRowset1->GetTxnJoin(), S_OK))
|
|
{
|
|
if (CHECK(m_pChgUpdRowset1->m_pITxnJoin->JoinTransaction ( pITransaction,
|
|
m_fIsoLevel,
|
|
0,
|
|
NULL
|
|
), S_OK))
|
|
{
|
|
m_pChgUpdRowset1->m_fTxnStarted = TRUE;
|
|
|
|
hr=m_pChgUpdRowset1->MakeRowset();
|
|
if (!(hr==S_OK||hr==DB_S_ERRORSOCCURRED))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
|
|
//Make a change
|
|
if (!COMPARE(Change(m_pChgUpdRowset1), TRUE))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
|
|
//Commit with fRetaining = FALSE, we should then be in autocommit
|
|
if (!CHECK(m_pChgUpdRowset1->CommitCoord(FALSE, pITransaction,m_pChgUpdRowset1->m_pITxnJoin), S_OK))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
m_pChgUpdRowset1->m_fTxnStarted = FALSE;
|
|
|
|
//Sleep for a few seconds; this is to ensure that the back end has had
|
|
//time to make this update visible to other transactions which
|
|
//should see it. This is only necessary for Access, which only does
|
|
//this every few seconds.
|
|
if (m_fOnAccess)
|
|
Sleep(SLEEP_TIME); //Takes milliseconds as param
|
|
|
|
//Verify pending row after commit
|
|
if (!m_pChgUpdRowset1->CheckPendingRow(1))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
|
|
//Use second rowset to verify we can't see
|
|
//the change since we haven't updated yet
|
|
if (!COMPARE(FindChange(m_pChgUpdRowset2), FALSE))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
|
|
//delete second rowset in case it will be used again in this variation
|
|
if (!CHECK(m_pChgUpdRowset2->FreeRowset(), S_OK))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
|
|
//the following is commented out because preserve does not apply to distributed txns
|
|
//it has yet to be decided whether sessions will be preserved at commit/abort
|
|
//until then it is provider specific where the session is preserved or not with no way to determine this before doing it
|
|
// if (m_pChgUpdRowset1->m_fCommitPreserve)
|
|
// {
|
|
hExpectedHR = S_OK;
|
|
// }
|
|
// else
|
|
// {
|
|
// hExpectedHR = E_UNEXPECTED;
|
|
// }
|
|
|
|
//Call update for all pending changes
|
|
if (!CHECK(m_pChgUpdRowset1->m_pIRowsetUpdate->Update( NULL,
|
|
0,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL), hExpectedHR))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
|
|
//if the session zombied then this should return an error
|
|
//if the session didn't zombie then this is ok and change goto back end (autocommit mode at this point)
|
|
g_ulLastActualInsert++;
|
|
g_ulLastActualDelete++;//g_DeleteAndInsertIncrement();
|
|
|
|
//Commit the update (no matter if it succedded or not)
|
|
//shouldn't work, retaining is FALSE, there is no current transaction
|
|
if (!CHECK(m_pChgUpdRowset1->CommitCoord(FALSE, pITransaction,m_pChgUpdRowset1->m_pITxnJoin), XACT_E_NOTRANSACTION))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
if (!CHECK(m_pChgUpdRowset1->AbortCoord(FALSE, pITransaction,m_pChgUpdRowset1->m_pITxnJoin), XACT_E_NOTRANSACTION))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
|
|
//Sleep for a few seconds; this is to ensure that the back end has had
|
|
//time to make this update visible to other transactions which
|
|
//should see it. This is only necessary for Access, which only does
|
|
//this every few seconds.
|
|
if (m_fOnAccess)
|
|
Sleep(SLEEP_TIME); //Takes milliseconds as param
|
|
|
|
//the following is commented out because preserve does not apply to distributed txns
|
|
//it has yet to be decided whether sessions will be preserved at commit/abort
|
|
//until then it is provider specific where the session is preserved or not with no way to determine this before doing it
|
|
// if (m_pChgUpdRowset1->m_fCommitPreserve)
|
|
// {
|
|
//We should now be able to see the change since we updated
|
|
//and our change from before the commit should have been
|
|
//preserved
|
|
if (!COMPARE(FindChange(m_pChgUpdRowset2), TRUE))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
// }
|
|
// else
|
|
// {
|
|
// //We shouldn't see a change because the rowset
|
|
// //should have zomibied on commit, losing the pending change
|
|
// if (!COMPARE(FindChange(m_pChgUpdRowset2), FALSE))
|
|
// {
|
|
// goto CLEANUP;
|
|
// }
|
|
// }
|
|
}
|
|
}
|
|
}
|
|
//Everything went OK
|
|
fResults = TRUE;
|
|
CLEANUP:
|
|
CHECK(m_pChgUpdRowset1->FreeRowset(), S_OK);
|
|
CHECK(m_pChgUpdRowset2->FreeRowset(), S_OK);
|
|
|
|
//free objects;
|
|
m_pChgUpdRowset1->FreeJoinTxn();
|
|
if (pITransaction)
|
|
{
|
|
m_pChgUpdRowset1->FreeCoordTxn(pITransaction);
|
|
pITransaction = NULL;
|
|
}
|
|
m_pChgUpdRowset2->FreeJoinTxn();
|
|
if (pITransaction)
|
|
{
|
|
m_pChgUpdRowset2->FreeCoordTxn(pITransaction);
|
|
pITransaction = NULL;
|
|
}
|
|
ReleaseAllRowsetsAndTxns();
|
|
|
|
if (fResults)
|
|
return TEST_PASS;
|
|
else
|
|
return TEST_FAIL;
|
|
}
|
|
|
|
|
|
// }}
|
|
// {{ TCW_VAR_PROTOTYPE(4)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc Change, Update, Commit with fRetaining = FALSE
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCIRowsetUpdate::Variation_4()
|
|
{
|
|
BOOL fResults = FALSE;
|
|
HRESULT hr;
|
|
ITransaction *pITransaction = NULL;
|
|
|
|
//if provider does not support IRowsetChange
|
|
if (!m_pChgUpdRowset1->m_fChange)
|
|
{
|
|
odtLog << L"IRowsetChange not supported" << wszNewLine;
|
|
fResults = TRUE;
|
|
goto CLEANUP;
|
|
}
|
|
|
|
//start coordinated txn & join it
|
|
if (CHECK(m_pChgUpdRowset1->StartCoordTxn(&pITransaction,m_fIsoLevel), TRUE))
|
|
{
|
|
//get transactionjoin transaction object.
|
|
if (CHECK(m_pChgUpdRowset1->GetTxnJoin(), S_OK))
|
|
{
|
|
if (CHECK(m_pChgUpdRowset1->m_pITxnJoin->JoinTransaction ( pITransaction,
|
|
m_fIsoLevel,
|
|
0,
|
|
NULL
|
|
), S_OK))
|
|
{
|
|
m_pChgUpdRowset1->m_fTxnStarted = TRUE;
|
|
|
|
hr=m_pChgUpdRowset1->MakeRowset();
|
|
if (!(hr==S_OK||hr==DB_S_ERRORSOCCURRED))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
|
|
//Make a change
|
|
if (!COMPARE(Change(m_pChgUpdRowset1), TRUE))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
|
|
//Call update for all pending changes
|
|
if (!CHECK(m_pChgUpdRowset1->m_pIRowsetUpdate->Update(NULL, 0,
|
|
NULL, NULL, NULL, NULL), S_OK))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
|
|
//Commit the change, with fRetaining = FALSE
|
|
if (!CHECK(m_pChgUpdRowset1->CommitCoord(FALSE, pITransaction,m_pChgUpdRowset1->m_pITxnJoin), S_OK))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
m_pChgUpdRowset1->m_fTxnStarted = FALSE;
|
|
|
|
g_ulLastActualInsert++;
|
|
g_ulLastActualDelete++;//g_DeleteAndInsertIncrement();
|
|
|
|
//Sleep for a few seconds; this is to ensure that the back end has had
|
|
//time to make this update visible to other transactions which
|
|
//should see it. This is only necessary for Access, which only does
|
|
//this every few seconds.
|
|
if (m_fOnAccess)
|
|
Sleep(SLEEP_TIME); //Takes milliseconds as param
|
|
|
|
//Verify no pending row
|
|
if (!m_pChgUpdRowset1->CheckPendingRow(0))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
|
|
//Use second rowset to verify we can see the change
|
|
if (!COMPARE(FindChange(m_pChgUpdRowset2), TRUE))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
//Everything went OK
|
|
fResults = TRUE;
|
|
CLEANUP:
|
|
CHECK(m_pChgUpdRowset1->FreeRowset(), S_OK);
|
|
CHECK(m_pChgUpdRowset2->FreeRowset(), S_OK);
|
|
|
|
//free objects;
|
|
m_pChgUpdRowset1->FreeJoinTxn();
|
|
if (pITransaction)
|
|
{
|
|
m_pChgUpdRowset1->FreeCoordTxn(pITransaction);
|
|
pITransaction = NULL;
|
|
}
|
|
m_pChgUpdRowset2->FreeJoinTxn();
|
|
if (pITransaction)
|
|
{
|
|
m_pChgUpdRowset2->FreeCoordTxn(pITransaction);
|
|
pITransaction = NULL;
|
|
}
|
|
ReleaseAllRowsetsAndTxns();
|
|
|
|
if (fResults)
|
|
return TEST_PASS;
|
|
else
|
|
return TEST_FAIL;
|
|
}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(5)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc Open read only rowset
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCIRowsetUpdate::Variation_5()
|
|
{
|
|
BOOL fResults = FALSE;
|
|
HRESULT hr;
|
|
ITransaction *pITransaction = NULL;
|
|
|
|
//if provider does not support IRowsetChange
|
|
if (!m_pChgUpdRowset1->m_fChange)
|
|
{
|
|
odtLog << L"IRowsetChange not supported" << wszNewLine;
|
|
fResults = TRUE;
|
|
goto CLEANUP;
|
|
}
|
|
|
|
//start coordinated txn & join it
|
|
if (CHECK(m_pChgUpdRowset1->StartCoordTxn(&pITransaction,m_fIsoLevel), TRUE))
|
|
{
|
|
//get transactionjoin transaction object.
|
|
if (CHECK(m_pChgUpdRowset1->GetTxnJoin(), S_OK))
|
|
{
|
|
if (CHECK(m_pChgUpdRowset1->m_pITxnJoin->JoinTransaction ( pITransaction,
|
|
m_fIsoLevel,
|
|
0,
|
|
NULL
|
|
), S_OK))
|
|
{
|
|
m_pChgUpdRowset1->m_fTxnStarted = TRUE;
|
|
|
|
hr=m_pChgUpdRowset1->MakeRowsetReadOnly();
|
|
if (!(hr==S_OK||hr==DB_S_ERRORSOCCURRED))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
//Commit the change to end the dist txn
|
|
if (!CHECK(m_pChgUpdRowset1->CommitCoord(FALSE, pITransaction,m_pChgUpdRowset1->m_pITxnJoin), S_OK))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
m_pChgUpdRowset1->m_fTxnStarted = FALSE;
|
|
fResults = TRUE;
|
|
CLEANUP:
|
|
CHECK(m_pChgUpdRowset1->FreeRowset(), S_OK);
|
|
|
|
//free objects;
|
|
m_pChgUpdRowset1->FreeJoinTxn();
|
|
if (pITransaction)
|
|
{
|
|
m_pChgUpdRowset1->FreeCoordTxn(pITransaction);
|
|
pITransaction = NULL;
|
|
}
|
|
m_pChgUpdRowset2->FreeJoinTxn();
|
|
if (pITransaction)
|
|
{
|
|
m_pChgUpdRowset2->FreeCoordTxn(pITransaction);
|
|
pITransaction = NULL;
|
|
}
|
|
ReleaseAllRowsetsAndTxns();
|
|
|
|
if (fResults)
|
|
return TEST_PASS;
|
|
else
|
|
return TEST_FAIL;
|
|
}
|
|
// }}
|
|
// }}
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(6)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc Change, Join Txn, Update, Abort with fRetaining = FALSE
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCIRowsetUpdate::Variation_6()
|
|
{
|
|
BOOL fResults = FALSE;
|
|
HRESULT hr;
|
|
ITransaction *pITransaction = NULL;
|
|
|
|
//if provider does not support IRowsetChange
|
|
if (!m_pChgUpdRowset1->m_fChange)
|
|
{
|
|
odtLog << L"IRowsetChange not supported" << wszNewLine;
|
|
fResults = TRUE;
|
|
goto CLEANUP;
|
|
}
|
|
|
|
hr=m_pChgUpdRowset1->MakeRowset();
|
|
if (!(hr==S_OK||hr==DB_S_ERRORSOCCURRED))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
|
|
//pretend the txn is started here so the change is not recored yet by this test
|
|
m_pChgUpdRowset1->m_fTxnStarted = TRUE;
|
|
//Make a change
|
|
if (!COMPARE(Change(m_pChgUpdRowset1), TRUE))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
|
|
//start coordinated txn & join it
|
|
if (CHECK(m_pChgUpdRowset1->StartCoordTxn(&pITransaction,m_fIsoLevel), TRUE))
|
|
{
|
|
//get transactionjoin transaction object.
|
|
if (CHECK(m_pChgUpdRowset1->GetTxnJoin(), S_OK))
|
|
{
|
|
if (CHECK(m_pChgUpdRowset1->m_pITxnJoin->JoinTransaction ( pITransaction,
|
|
m_fIsoLevel,
|
|
0,
|
|
NULL
|
|
), S_OK))
|
|
{
|
|
m_pChgUpdRowset1->m_fTxnStarted = TRUE;
|
|
|
|
if (!CHECK(m_pChgUpdRowset1->m_pIRowsetUpdate->Update( NULL,
|
|
0,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL), S_OK))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
|
|
//Abort the change, with fRetaining = FALSE
|
|
if (!CHECK(m_pChgUpdRowset1->AbortCoord(FALSE, pITransaction,m_pChgUpdRowset1->m_pITxnJoin), S_OK))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
m_pChgUpdRowset1->m_fTxnStarted = FALSE;
|
|
|
|
//Sleep for a few seconds; this is to ensure that the back end has had
|
|
//time to make this update visible to other transactions which
|
|
//should see it. This is only necessary for Access, which only does
|
|
//this every few seconds.
|
|
if (m_fOnAccess)
|
|
Sleep(SLEEP_TIME); //Takes milliseconds as param
|
|
|
|
//Verify no pending row (or lack thereof) after the abort
|
|
//since we already called update
|
|
if (!m_pChgUpdRowset1->CheckPendingRow(0))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
|
|
//Use second rowset to verify we can't see the change
|
|
if (!COMPARE(FindChange(m_pChgUpdRowset2), FALSE))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
//Everything went OK
|
|
fResults = TRUE;
|
|
CLEANUP:
|
|
CHECK(m_pChgUpdRowset1->FreeRowset(), S_OK);
|
|
CHECK(m_pChgUpdRowset2->FreeRowset(), S_OK);
|
|
|
|
//free objects;
|
|
m_pChgUpdRowset1->FreeJoinTxn();
|
|
if (pITransaction)
|
|
{
|
|
m_pChgUpdRowset1->FreeCoordTxn(pITransaction);
|
|
pITransaction = NULL;
|
|
}
|
|
m_pChgUpdRowset2->FreeJoinTxn();
|
|
if (pITransaction)
|
|
{
|
|
m_pChgUpdRowset2->FreeCoordTxn(pITransaction);
|
|
pITransaction = NULL;
|
|
}
|
|
ReleaseAllRowsetsAndTxns();
|
|
|
|
if (fResults)
|
|
return TEST_PASS;
|
|
else
|
|
return TEST_FAIL;
|
|
}
|
|
// }}
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(7)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc Change, Update, Join Txn, Abort with fRetaining = FALSE
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCIRowsetUpdate::Variation_7()
|
|
{
|
|
BOOL fResults = FALSE;
|
|
HRESULT hr;
|
|
ITransaction *pITransaction = NULL;
|
|
|
|
//if provider does not support IRowsetChange
|
|
if (!m_pChgUpdRowset1->m_fChange)
|
|
{
|
|
odtLog << L"IRowsetChange not supported" << wszNewLine;
|
|
fResults = TRUE;
|
|
goto CLEANUP;
|
|
}
|
|
|
|
hr=m_pChgUpdRowset1->MakeRowset();
|
|
if (!(hr==S_OK||hr==DB_S_ERRORSOCCURRED))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
|
|
//Make a change
|
|
if (!COMPARE(Change(m_pChgUpdRowset1), TRUE))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
|
|
if (!CHECK(m_pChgUpdRowset1->m_pIRowsetUpdate->Update( NULL,
|
|
0,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL), S_OK))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
|
|
//start coordinated txn & join it
|
|
if (CHECK(m_pChgUpdRowset1->StartCoordTxn(&pITransaction,m_fIsoLevel), TRUE))
|
|
{
|
|
//get transactionjoin transaction object.
|
|
if (CHECK(m_pChgUpdRowset1->GetTxnJoin(), S_OK))
|
|
{
|
|
if (CHECK(m_pChgUpdRowset1->m_pITxnJoin->JoinTransaction ( pITransaction,
|
|
m_fIsoLevel,
|
|
0,
|
|
NULL
|
|
), S_OK))
|
|
{
|
|
m_pChgUpdRowset1->m_fTxnStarted = TRUE;
|
|
|
|
//Abort the change, with fRetaining = FALSE
|
|
if (!CHECK(m_pChgUpdRowset1->AbortCoord(FALSE, pITransaction,m_pChgUpdRowset1->m_pITxnJoin), S_OK))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
m_pChgUpdRowset1->m_fTxnStarted = FALSE;
|
|
|
|
//Sleep for a few seconds; this is to ensure that the back end has had
|
|
//time to make this update visible to other transactions which
|
|
//should see it. This is only necessary for Access, which only does
|
|
//this every few seconds.
|
|
if (m_fOnAccess)
|
|
Sleep(SLEEP_TIME); //Takes milliseconds as param
|
|
|
|
//Verify no pending row (or lack thereof) after the abort
|
|
//since we already called update
|
|
if (!m_pChgUpdRowset1->CheckPendingRow(0))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
|
|
//Use second rowset to verify we can see the change
|
|
if (!COMPARE(FindChange(m_pChgUpdRowset2), TRUE))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
//Everything went OK
|
|
fResults = TRUE;
|
|
CLEANUP:
|
|
CHECK(m_pChgUpdRowset1->FreeRowset(), S_OK);
|
|
CHECK(m_pChgUpdRowset2->FreeRowset(), S_OK);
|
|
|
|
//free objects;
|
|
m_pChgUpdRowset1->FreeJoinTxn();
|
|
if (pITransaction)
|
|
{
|
|
m_pChgUpdRowset1->FreeCoordTxn(pITransaction);
|
|
pITransaction = NULL;
|
|
}
|
|
m_pChgUpdRowset2->FreeJoinTxn();
|
|
if (pITransaction)
|
|
{
|
|
m_pChgUpdRowset2->FreeCoordTxn(pITransaction);
|
|
pITransaction = NULL;
|
|
}
|
|
ReleaseAllRowsetsAndTxns();
|
|
|
|
if (fResults)
|
|
return TEST_PASS;
|
|
else
|
|
return TEST_FAIL;
|
|
}
|
|
// }}
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(8)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc Change, Join Txn, Update, Commit with fRetaining = FALSE
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCIRowsetUpdate::Variation_8()
|
|
{
|
|
BOOL fResults = FALSE;
|
|
HRESULT hr;
|
|
ITransaction *pITransaction = NULL;
|
|
|
|
//if provider does not support IRowsetChange
|
|
if (!m_pChgUpdRowset1->m_fChange)
|
|
{
|
|
odtLog << L"IRowsetChange not supported" << wszNewLine;
|
|
fResults = TRUE;
|
|
goto CLEANUP;
|
|
}
|
|
|
|
hr=m_pChgUpdRowset1->MakeRowset();
|
|
if (!(hr==S_OK||hr==DB_S_ERRORSOCCURRED))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
|
|
//pretend the txn is started here so the change is not recored yet by this test
|
|
m_pChgUpdRowset1->m_fTxnStarted = TRUE;
|
|
//Make a change
|
|
if (!COMPARE(Change(m_pChgUpdRowset1), TRUE))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
|
|
//start coordinated txn & join it
|
|
if (CHECK(m_pChgUpdRowset1->StartCoordTxn(&pITransaction,m_fIsoLevel), TRUE))
|
|
{
|
|
//get transactionjoin transaction object.
|
|
if (CHECK(m_pChgUpdRowset1->GetTxnJoin(), S_OK))
|
|
{
|
|
if (CHECK(m_pChgUpdRowset1->m_pITxnJoin->JoinTransaction ( pITransaction,
|
|
m_fIsoLevel,
|
|
0,
|
|
NULL
|
|
), S_OK))
|
|
{
|
|
if (!CHECK(m_pChgUpdRowset1->m_pIRowsetUpdate->Update( NULL,
|
|
0,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL), S_OK))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
|
|
//Abort the change, with fRetaining = FALSE
|
|
if (!CHECK(m_pChgUpdRowset1->CommitCoord(FALSE, pITransaction,m_pChgUpdRowset1->m_pITxnJoin), S_OK))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
m_pChgUpdRowset1->m_fTxnStarted = FALSE;
|
|
g_ulLastActualInsert++;
|
|
g_ulLastActualDelete++;//g_DeleteAndInsertIncrement();
|
|
|
|
//Sleep for a few seconds; this is to ensure that the back end has had
|
|
//time to make this update visible to other transactions which
|
|
//should see it. This is only necessary for Access, which only does
|
|
//this every few seconds.
|
|
if (m_fOnAccess)
|
|
Sleep(SLEEP_TIME); //Takes milliseconds as param
|
|
|
|
//Verify no pending row (or lack thereof) after the abort
|
|
//since we already called update
|
|
if (!m_pChgUpdRowset1->CheckPendingRow(0))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
|
|
//Use second rowset to verify we can see the change
|
|
if (!COMPARE(FindChange(m_pChgUpdRowset2), TRUE))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
//Everything went OK
|
|
fResults = TRUE;
|
|
CLEANUP:
|
|
CHECK(m_pChgUpdRowset1->FreeRowset(), S_OK);
|
|
CHECK(m_pChgUpdRowset2->FreeRowset(), S_OK);
|
|
|
|
//free objects;
|
|
m_pChgUpdRowset1->FreeJoinTxn();
|
|
if (pITransaction)
|
|
{
|
|
m_pChgUpdRowset1->FreeCoordTxn(pITransaction);
|
|
pITransaction = NULL;
|
|
}
|
|
m_pChgUpdRowset2->FreeJoinTxn();
|
|
if (pITransaction)
|
|
{
|
|
m_pChgUpdRowset2->FreeCoordTxn(pITransaction);
|
|
pITransaction = NULL;
|
|
}
|
|
ReleaseAllRowsetsAndTxns();
|
|
|
|
if (fResults)
|
|
return TEST_PASS;
|
|
else
|
|
return TEST_FAIL;
|
|
}
|
|
// }}
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(9)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc Change, Update, Join Txn, Abort with fRetaining = FALSE
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCIRowsetUpdate::Variation_9()
|
|
{
|
|
BOOL fResults = FALSE;
|
|
HRESULT hr;
|
|
ITransaction *pITransaction = NULL;
|
|
|
|
//if provider does not support IRowsetChange
|
|
if (!m_pChgUpdRowset1->m_fChange)
|
|
{
|
|
odtLog << L"IRowsetChange not supported" << wszNewLine;
|
|
fResults = TRUE;
|
|
goto CLEANUP;
|
|
}
|
|
|
|
hr=m_pChgUpdRowset1->MakeRowset();
|
|
if (!(hr==S_OK||hr==DB_S_ERRORSOCCURRED))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
|
|
//Make a change
|
|
if (!COMPARE(Change(m_pChgUpdRowset1), TRUE))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
|
|
if (!CHECK(m_pChgUpdRowset1->m_pIRowsetUpdate->Update( NULL,
|
|
0,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL), S_OK))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
|
|
//start coordinated txn & join it
|
|
if (CHECK(m_pChgUpdRowset1->StartCoordTxn(&pITransaction,m_fIsoLevel), TRUE))
|
|
{
|
|
//get transactionjoin transaction object.
|
|
if (CHECK(m_pChgUpdRowset1->GetTxnJoin(), S_OK))
|
|
{
|
|
if (CHECK(m_pChgUpdRowset1->m_pITxnJoin->JoinTransaction ( pITransaction,
|
|
m_fIsoLevel,
|
|
0,
|
|
NULL
|
|
), S_OK))
|
|
{
|
|
m_pChgUpdRowset1->m_fTxnStarted = TRUE;
|
|
|
|
//Abort the change, with fRetaining = FALSE
|
|
if (!CHECK(m_pChgUpdRowset1->AbortCoord(FALSE, pITransaction,m_pChgUpdRowset1->m_pITxnJoin), S_OK))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
m_pChgUpdRowset1->m_fTxnStarted = FALSE;
|
|
|
|
//Sleep for a few seconds; this is to ensure that the back end has had
|
|
//time to make this update visible to other transactions which
|
|
//should see it. This is only necessary for Access, which only does
|
|
//this every few seconds.
|
|
if (m_fOnAccess)
|
|
Sleep(SLEEP_TIME); //Takes milliseconds as param
|
|
|
|
//Verify no pending row (or lack thereof) after the abort
|
|
//since we already called update
|
|
if (!m_pChgUpdRowset1->CheckPendingRow(0))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
|
|
//Use second rowset to verify we can see the change
|
|
if (!COMPARE(FindChange(m_pChgUpdRowset2), TRUE))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
//Everything went OK
|
|
fResults = TRUE;
|
|
CLEANUP:
|
|
CHECK(m_pChgUpdRowset1->FreeRowset(), S_OK);
|
|
CHECK(m_pChgUpdRowset2->FreeRowset(), S_OK);
|
|
|
|
//free objects;
|
|
m_pChgUpdRowset1->FreeJoinTxn();
|
|
if (pITransaction)
|
|
{
|
|
m_pChgUpdRowset1->FreeCoordTxn(pITransaction);
|
|
pITransaction = NULL;
|
|
}
|
|
m_pChgUpdRowset2->FreeJoinTxn();
|
|
if (pITransaction)
|
|
{
|
|
m_pChgUpdRowset2->FreeCoordTxn(pITransaction);
|
|
pITransaction = NULL;
|
|
}
|
|
ReleaseAllRowsetsAndTxns();
|
|
|
|
if (fResults)
|
|
return TEST_PASS;
|
|
else
|
|
return TEST_FAIL;
|
|
}
|
|
// }}
|
|
|
|
// {{ TCW_TERMINATE_METHOD
|
|
//--------------------------------------------------------------------
|
|
// @mfunc TestCase Termination Routine
|
|
//
|
|
// @rdesc TRUE or FALSE
|
|
//
|
|
BOOL TCIRowsetUpdate::Terminate()
|
|
{
|
|
// TO DO: Add your own code here
|
|
|
|
// {{ TCW_TERM_BASECLASS_CHECK2
|
|
return(CTxnUpdate::Terminate());
|
|
} // }}
|
|
// }}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_TC_PROTOTYPE(CNoTxn)
|
|
//*-----------------------------------------------------------------------
|
|
//| Test Case: CNoTxn - Abort and Commit called before StartTransaction
|
|
//| Created: 05/14/96
|
|
//*-----------------------------------------------------------------------
|
|
|
|
//--------------------------------------------------------------------
|
|
// @mfunc TestCase Initialization Routine
|
|
//
|
|
// @rdesc TRUE or FALSE
|
|
//
|
|
BOOL CNoTxn::Init()
|
|
{
|
|
// {{ TCW_INIT_BASECLASS_CHECK
|
|
if(CTxnImmed::Init())
|
|
// }}
|
|
{
|
|
//the jet engine (access) does not support distributed transactions
|
|
if (m_fOnAccess)
|
|
{
|
|
return TEST_SKIPPED;
|
|
}
|
|
else
|
|
{
|
|
return TEST_PASS;
|
|
}
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(1)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc Start a coordinated txn, make a change, abort it, look for change
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int CNoTxn::Variation_1()
|
|
{
|
|
ITransaction *pITransaction = NULL;
|
|
HRESULT hr;
|
|
IRowset *pIRowset = NULL;
|
|
BOOL fResults = TEST_FAIL;
|
|
|
|
//start coordinated txn & join it
|
|
if (!CHECK(m_pChgRowset1->StartCoordTxn(&pITransaction,m_fIsoLevel), TRUE))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
|
|
hr=m_pChgRowset1->MakeRowset();
|
|
if (!(hr==S_OK||hr==DB_S_ERRORSOCCURRED))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
|
|
//if provider does not support IRowsetChange
|
|
if (!m_pChgRowset1->m_fChange)
|
|
{
|
|
if(!CHECK((m_pChgRowset1->m_pTable)->Update(GetNextRowToInsert()), S_OK))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//Do something in txn
|
|
if(!COMPARE(Change(m_pChgRowset1), TRUE))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
}
|
|
|
|
//Try to abort when the session never joined the coordinated Transaction
|
|
hr=pITransaction->Abort(NULL, FALSE, FALSE);
|
|
|
|
//the following is commented out because preserve does not apply to distributed txns
|
|
//it has yet to be decided whether sessions will be preserved at commit/abort
|
|
//until then it is provider specific where the session is preserved or not with no way to determine this before doing it
|
|
// if (!m_pChgRowset1->m_fAbortPreserve)
|
|
// {
|
|
// if (!VerifyInterface(m_pChgRowset1->m_pIAccessor, IID_IRowset, ROWSET_INTERFACE,(IUnknown **)&pIRowset))
|
|
// {
|
|
// goto CLEANUP;
|
|
// }
|
|
// hr=pIRowset->RestartPosition(NULL);
|
|
// if(DB_S_COMMANDREEXECUTED!=hr&&S_OK!=hr)//rowset should not be zombied, transaction not on session
|
|
// {
|
|
// goto CLEANUP;
|
|
// }
|
|
// //Cleanup rowsets and start with new ones, in case the first ones
|
|
// //were zombied
|
|
// }
|
|
|
|
//if provider does not support IRowsetChange
|
|
if (m_pChgRowset1->m_fChange)
|
|
{
|
|
//verify we can see the change, this session is not enlisted
|
|
if (!COMPARE(FindChange(m_pChgRowset1), TRUE))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (!COMPARE(m_pChgRowset1->FindRow(g_ulLastActualInsert, NULL), TRUE))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
}
|
|
fResults = TEST_PASS;
|
|
CLEANUP:
|
|
SAFE_RELEASE(pIRowset);
|
|
if (pITransaction)
|
|
{
|
|
m_pChgRowset1->FreeCoordTxn(pITransaction);
|
|
pITransaction = NULL;
|
|
}
|
|
|
|
return fResults;
|
|
}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(2)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc Make a change, start a coordinated txn, join it, abort it, look for change
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int CNoTxn::Variation_2()
|
|
{
|
|
ITransaction *pITransaction = NULL;
|
|
HRESULT hr;
|
|
IRowset *pIRowset = NULL;
|
|
BOOL fResults = FALSE;
|
|
|
|
hr=m_pChgRowset1->MakeRowset();
|
|
if (!(hr==S_OK||hr==DB_S_ERRORSOCCURRED))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
|
|
//if provider does not support IRowsetChange
|
|
if (!m_pChgRowset1->m_fChange)
|
|
{
|
|
if(!CHECK((m_pChgRowset1->m_pTable)->Update(GetNextRowToInsert()), S_OK))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//Do something in txn
|
|
if(!COMPARE(Change(m_pChgRowset1), TRUE))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
}
|
|
|
|
|
|
//start coordinated txn & join it
|
|
if (!CHECK(m_pChgRowset1->StartCoordTxn(&pITransaction,m_fIsoLevel), TRUE))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
|
|
//get transactionjoin transaction object.
|
|
if (CHECK(m_pChgRowset1->GetTxnJoin(), S_OK))
|
|
{
|
|
m_hr = m_pChgRowset1->m_pITxnJoin->JoinTransaction ( pITransaction,
|
|
m_fIsoLevel,
|
|
0,
|
|
NULL
|
|
);
|
|
//some providers do not allow joining a txn with open rowsets
|
|
if (m_hr==XACT_E_XTIONEXISTS)
|
|
{
|
|
fResults = TEST_PASS;
|
|
goto CLEANUP;
|
|
}
|
|
if (m_hr != S_OK)
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
|
|
//Try to abort the joined and the coordinated Transaction
|
|
hr=pITransaction->Abort(NULL, FALSE, FALSE);
|
|
|
|
//the following is commented out because preserve does not apply to distributed txns
|
|
//it has yet to be decided whether sessions will be preserved at commit/abort
|
|
//until then it is provider specific where the session is preserved or not with no way to determine this before doing it
|
|
// if (!m_pChgRowset1->m_fAbortPreserve)
|
|
// {
|
|
// if (!VerifyInterface(m_pChgRowset1->m_pIAccessor, IID_IRowset, ROWSET_INTERFACE,(IUnknown **)&pIRowset))
|
|
// {
|
|
// goto CLEANUP;
|
|
// }
|
|
// m_hr=pIRowset->RestartPosition(NULL);
|
|
// COMPARE(m_hr,E_UNEXPECTED);//expecting E_UNEXPECTED if the is zombied
|
|
// //Cleanup rowsets and start with new ones, in case the first ones
|
|
// //were zombied
|
|
// m_pChgRowset1->ReleaseRowsetObject();
|
|
// hr=m_pChgRowset1->MakeRowset();
|
|
// if (!(hr==S_OK||hr==DB_S_ERRORSOCCURRED))
|
|
// {
|
|
// goto CLEANUP;
|
|
// }
|
|
// }
|
|
|
|
|
|
//session might be zombied here, should it be???????
|
|
//best fix it till we know for sure
|
|
//unenlist the session from the dead dist txn
|
|
if (!CHECK(m_pChgRowset1->m_pITxnJoin->JoinTransaction ( NULL,
|
|
ISOLATIONLEVEL_UNSPECIFIED,
|
|
0,
|
|
NULL
|
|
),S_OK))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
ReleaseAllRowsets();
|
|
hr=m_pChgRowset1->MakeRowset();
|
|
if (!(hr==S_OK||hr==DB_S_ERRORSOCCURRED))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
|
|
//if provider does not support IRowsetChange
|
|
if (m_pChgRowset1->m_fChange)
|
|
{
|
|
//verify we can see the change, this session is not enlisted
|
|
if (!COMPARE(FindChange(m_pChgRowset1), TRUE))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (!COMPARE(m_pChgRowset1->FindRow(g_ulLastActualInsert, NULL), TRUE))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
}
|
|
}
|
|
fResults = TEST_PASS;
|
|
CLEANUP:
|
|
ReleaseAllRowsetsAndTxns();
|
|
SAFE_RELEASE(pIRowset); m_pChgRowset1->FreeJoinTxn();
|
|
if (pITransaction)
|
|
{
|
|
m_pChgRowset1->FreeCoordTxn(pITransaction);
|
|
pITransaction = NULL;
|
|
}
|
|
return fResults;
|
|
}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(3)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc Make a change, start a coordinated txn, join it, commit it, look for change
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int CNoTxn::Variation_3()
|
|
{
|
|
ITransaction *pITransaction = NULL;
|
|
HRESULT hr;
|
|
IRowset *pIRowset = NULL;
|
|
BOOL fResults = TEST_FAIL;
|
|
|
|
hr=m_pChgRowset1->MakeRowset();
|
|
if (!(hr==S_OK||hr==DB_S_ERRORSOCCURRED))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
|
|
//if provider does not support IRowsetChange
|
|
if (!m_pChgRowset1->m_fChange)
|
|
{
|
|
if(!CHECK((m_pChgRowset1->m_pTable)->Update(GetNextRowToInsert()), S_OK))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//Do something in txn
|
|
if(!COMPARE(Change(m_pChgRowset1), TRUE))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
}
|
|
|
|
//start coordinated txn & join it
|
|
if (!CHECK(m_pChgRowset1->StartCoordTxn(&pITransaction,m_fIsoLevel), TRUE))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
|
|
//get transactionjoin transaction object.
|
|
if (CHECK(m_pChgRowset1->GetTxnJoin(), S_OK))
|
|
{
|
|
if (CHECK(m_pChgRowset1->m_pITxnJoin->JoinTransaction ( pITransaction,
|
|
m_fIsoLevel,
|
|
0,
|
|
NULL
|
|
), S_OK))
|
|
{
|
|
//Try to Commit the joined and the coordinated Transaction, shouldn't
|
|
//affect change no matter
|
|
hr=pITransaction->Commit(FALSE, FALSE, FALSE);
|
|
|
|
//the following is commented out because preserve does not apply to distributed txns
|
|
//it has yet to be decided whether sessions will be preserved at commit/abort
|
|
//until then it is provider specific where the session is preserved or not with no way to determine this before doing it
|
|
// if (!m_pChgRowset1->m_fCommitPreserve)
|
|
// {
|
|
// if (!VerifyInterface(m_pChgRowset1->m_pIAccessor, IID_IRowset, ROWSET_INTERFACE,(IUnknown **)&pIRowset))
|
|
// {
|
|
// goto CLEANUP;
|
|
// }
|
|
// COMPARE(pIRowset->RestartPosition(NULL),E_UNEXPECTED);//expecting E_UNEXPECTED if the is zombied
|
|
// //Cleanup rowsets and start with new ones, in case the first ones
|
|
// //were zombied
|
|
// m_pChgRowset1->ReleaseRowsetObject();
|
|
// hr=m_pChgRowset1->MakeRowset();
|
|
// if (!(hr==S_OK||hr==DB_S_ERRORSOCCURRED))
|
|
// {
|
|
// goto CLEANUP;
|
|
// }
|
|
// }
|
|
|
|
//session might be zombied here, should it be???????
|
|
//best fix it till we know for sure
|
|
//unenlist the session from the dead dist txn
|
|
if (!CHECK(m_pChgRowset1->m_pITxnJoin->JoinTransaction ( NULL,
|
|
ISOLATIONLEVEL_UNSPECIFIED,
|
|
0,
|
|
NULL
|
|
),S_OK))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
ReleaseAllRowsets();
|
|
hr=m_pChgRowset1->MakeRowset();
|
|
if (!(hr==S_OK||hr==DB_S_ERRORSOCCURRED))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
|
|
|
|
//if provider does not support IRowsetChange
|
|
if (m_pChgRowset1->m_fChange)
|
|
{
|
|
//verify we can see the change, this session is not enlisted
|
|
if (!COMPARE(FindChange(m_pChgRowset1), TRUE))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (!COMPARE(m_pChgRowset1->FindRow(g_ulLastActualInsert, NULL), TRUE))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
fResults = TEST_PASS;
|
|
CLEANUP:
|
|
SAFE_RELEASE(pIRowset);
|
|
m_pChgRowset1->FreeJoinTxn();
|
|
if (pITransaction)
|
|
{
|
|
m_pChgRowset1->FreeCoordTxn(pITransaction);
|
|
pITransaction = NULL;
|
|
}
|
|
return fResults;
|
|
}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(4)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc GetOptionsObject before StartTransaction - S_OK
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int CNoTxn::Variation_4()
|
|
{
|
|
BOOL fResults = FALSE;
|
|
XACTOPT TxnOptions;
|
|
ITransactionOptions *pITxnOptions = NULL;
|
|
|
|
//get transactionjoin transaction object.
|
|
if (CHECK(m_pChgRowset1->GetTxnJoin(), S_OK))
|
|
{
|
|
//Try to GetOptionsObject when we've never called StartTransaction
|
|
if (CHECK(m_pChgRowset1->m_pITxnJoin->GetOptionsObject(&pITxnOptions), S_OK))
|
|
{
|
|
//Make sure we can also get the options
|
|
if (CHECK(pITxnOptions->GetOptions(&TxnOptions), S_OK))
|
|
{
|
|
fResults = TRUE;
|
|
}
|
|
if(pITxnOptions){pITxnOptions->Release();}
|
|
}
|
|
}
|
|
m_pChgRowset1->FreeJoinTxn();
|
|
if (fResults)
|
|
return TEST_PASS;
|
|
else
|
|
return TEST_FAIL;
|
|
}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(5)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc Start a coordinated txn, make a change, join the coord txn, abort it, look for change
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int CNoTxn::Variation_5()
|
|
{
|
|
ITransaction *pITransaction = NULL;
|
|
HRESULT hr;
|
|
IRowset *pIRowset = NULL;
|
|
BOOL fResults = FALSE;
|
|
|
|
//start coordinated txn & join it
|
|
if (!CHECK(m_pChgRowset1->StartCoordTxn(&pITransaction,m_fIsoLevel), TRUE))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
|
|
hr=m_pChgRowset1->MakeRowset();
|
|
if (!(hr==S_OK||hr==DB_S_ERRORSOCCURRED))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
|
|
//if provider does not support IRowsetChange
|
|
if (!m_pChgRowset1->m_fChange)
|
|
{
|
|
if(!CHECK((m_pChgRowset1->m_pTable)->Update(GetNextRowToInsert()), S_OK))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//Do something in txn
|
|
if(!COMPARE(Change(m_pChgRowset1), TRUE))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
}
|
|
|
|
//get transactionjoin transaction object.
|
|
if (CHECK(m_pChgRowset1->GetTxnJoin(), S_OK))
|
|
{
|
|
if (CHECK(m_pChgRowset1->m_pITxnJoin->JoinTransaction ( pITransaction,
|
|
m_fIsoLevel,
|
|
0,
|
|
NULL
|
|
), S_OK))
|
|
{
|
|
//Try to abort the joined and the coordinated Transaction
|
|
hr=pITransaction->Abort(NULL, FALSE, FALSE);
|
|
|
|
//the following is commented out because preserve does not apply to distributed txns
|
|
//it has yet to be decided whether sessions will be preserved at commit/abort
|
|
//until then it is provider specific where the session is preserved or not with no way to determine this before doing it
|
|
// if (!m_pChgRowset1->m_fAbortPreserve)
|
|
// {
|
|
// if (!VerifyInterface(m_pChgRowset1->m_pIAccessor, IID_IRowset, ROWSET_INTERFACE,(IUnknown **)&pIRowset))
|
|
// {
|
|
// goto CLEANUP;
|
|
// }
|
|
// COMPARE(pIRowset->RestartPosition(NULL),E_UNEXPECTED);//expecting E_UNEXPECTED if the is zombied
|
|
// //Cleanup rowsets and start with new ones, in case the first ones
|
|
// //were zombied
|
|
// m_pChgRowset1->ReleaseRowsetObject();
|
|
// hr=m_pChgRowset1->MakeRowset();
|
|
// if (!(hr==S_OK||hr==DB_S_ERRORSOCCURRED))
|
|
// {
|
|
/// goto CLEANUP;
|
|
// }
|
|
// }
|
|
|
|
//session might be zombied here, should it be???????
|
|
//best fix it till we know for sure
|
|
//unenlist the session from the dead dist txn
|
|
if (!CHECK(m_pChgRowset1->m_pITxnJoin->JoinTransaction ( NULL,
|
|
ISOLATIONLEVEL_UNSPECIFIED,
|
|
0,
|
|
NULL
|
|
),S_OK))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
ReleaseAllRowsets();
|
|
hr=m_pChgRowset1->MakeRowset();
|
|
if (!(hr==S_OK||hr==DB_S_ERRORSOCCURRED))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
|
|
//if provider does not support IRowsetChange
|
|
if (m_pChgRowset1->m_fChange)
|
|
{
|
|
//verify we can see the change, this session is not enlisted
|
|
if (!COMPARE(FindChange(m_pChgRowset1), TRUE))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (!COMPARE(m_pChgRowset1->FindRow(g_ulLastActualInsert, NULL), TRUE))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
fResults = TEST_PASS;
|
|
CLEANUP:
|
|
SAFE_RELEASE(pIRowset);
|
|
m_pChgRowset1->FreeJoinTxn();
|
|
if (pITransaction)
|
|
{
|
|
m_pChgRowset1->FreeCoordTxn(pITransaction);
|
|
pITransaction = NULL;
|
|
}
|
|
return fResults;
|
|
}
|
|
// }}
|
|
// {{ TCW_TERMINATE_METHOD
|
|
//--------------------------------------------------------------------
|
|
// @mfunc TestCase Termination Routine
|
|
//
|
|
// @rdesc TRUE or FALSE
|
|
//
|
|
BOOL CNoTxn::Terminate()
|
|
{
|
|
ReleaseDBSession();
|
|
ReleaseDataSourceObject();
|
|
|
|
// {{ TCW_TERM_BASECLASS_CHECK2
|
|
return(CTxnImmed::Terminate());
|
|
} // }}
|
|
// }}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_TC_PROTOTYPE(CMultipleTxns)
|
|
//*-----------------------------------------------------------------------
|
|
//| Test Case: CMultipleTxns - Multiple Transactions
|
|
//| Created: 05/14/96
|
|
//*-----------------------------------------------------------------------
|
|
|
|
//--------------------------------------------------------------------
|
|
// @mfunc TestCase Initialization Routine
|
|
//
|
|
// @rdesc TRUE or FALSE
|
|
//
|
|
BOOL CMultipleTxns::Init()
|
|
{
|
|
m_pTable = NULL;
|
|
m_ulCurrentDelete = 1;
|
|
m_ulCurrentInsert = NUM_ROWS+1;
|
|
|
|
// {{ TCW_INIT_BASECLASS_CHECK
|
|
if(CTxnImmed::Init())
|
|
// }}
|
|
{
|
|
//the jet engine (access) does not support distributed transactions
|
|
if (m_fOnAccess)
|
|
{
|
|
return TEST_SKIPPED;
|
|
}
|
|
else
|
|
{
|
|
CreateDBSession();
|
|
//Create a second table
|
|
m_pTable = new CTable(m_pIOpenRowset,(LPWSTR)gwszModuleName);
|
|
|
|
if (!m_pTable)
|
|
{
|
|
odtLog << wszMemoryAllocationError;
|
|
return FALSE;
|
|
}
|
|
|
|
//Start with a table with rows
|
|
if (FAILED(m_pTable->CreateTable(NUM_ROWS)))
|
|
return FALSE;
|
|
|
|
//Point second rowset at a second table so their are
|
|
//no conflicting locks -- we are only testing
|
|
//concurrent OLE DB objects here, not concurrent
|
|
//access to the same data.
|
|
//m_pChgRowset2 now owns the table in the db and will drop it.
|
|
m_pChgRowset2->SetTable(m_pTable, DELETETABLE_YES);
|
|
|
|
return TRUE;
|
|
}
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(1)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc Abort two sessions joined to a coord transactions on same DSO
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int CMultipleTxns::Variation_1()
|
|
{
|
|
BOOL fResults = FALSE;
|
|
HRESULT hr;
|
|
|
|
ITransaction *pITransaction = NULL;
|
|
IRowset *pIRowset = NULL;
|
|
|
|
//start coordinated txn & join it
|
|
if (CHECK(m_pChgRowset1->StartCoordTxn(&pITransaction,m_fIsoLevel), TRUE))
|
|
{
|
|
//get transactionjoin transaction object.
|
|
if (CHECK(m_pChgRowset1->GetTxnJoin(), S_OK))
|
|
{
|
|
if (CHECK(m_pChgRowset1->m_pITxnJoin->JoinTransaction ( pITransaction,
|
|
m_fIsoLevel,
|
|
0,
|
|
NULL
|
|
), S_OK))
|
|
{
|
|
//get 2nd transactionjoin transaction object.
|
|
if (CHECK(m_pChgRowset2->GetTxnJoin(), S_OK))
|
|
{
|
|
//join the coordinated txn from a 2nd session
|
|
if (CHECK(m_pChgRowset2->m_pITxnJoin->JoinTransaction ( pITransaction,
|
|
m_fIsoLevel,
|
|
0,
|
|
NULL
|
|
), S_OK))
|
|
{
|
|
hr=m_pChgRowset1->MakeRowset();
|
|
if (!(hr==S_OK||hr==DB_S_ERRORSOCCURRED))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
hr=m_pChgRowset2->MakeRowset();
|
|
if (!(hr==S_OK||hr==DB_S_ERRORSOCCURRED))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////
|
|
//Do something in each txn, abort 1, and verify change was aborted
|
|
//check 2 is then working normally
|
|
/////////////////////////////////////////////////////////////////////
|
|
|
|
//Rowset 1
|
|
//if provider does not support IRowsetChange
|
|
if (!m_pChgRowset1->m_fChange)
|
|
{
|
|
m_ulCurrentChangeRow = GetNextRowToInsert();
|
|
if(!CHECK((m_pChgRowset1->m_pTable)->Update(m_ulCurrentChangeRow,PRIMARY,TRUE,NULL,FALSE,g_ulFirstRowInTable), S_OK))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
|
|
if(!CHECK((m_pChgRowset2->m_pTable)->Update(m_ulCurrentChangeRow,PRIMARY,TRUE,NULL,FALSE,g_ulFirstRowInTable), S_OK))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//Make a change 1st session
|
|
if(!COMPARE(Change(m_pChgRowset1), TRUE))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
//Make a change, 2nd session
|
|
if(!COMPARE(m_pChgRowset2->Change(m_ulCurrentDelete, m_ulCurrentInsert), TRUE))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
}
|
|
//Now abort the whole thing (both sessions)
|
|
if (!CHECK(m_hr = m_pChgRowset1->AbortCoord(FALSE, pITransaction,m_pChgRowset1->m_pITxnJoin), S_OK))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
|
|
//unenlist the second session from the dead dist txn
|
|
if (!CHECK(m_pChgRowset2->m_pITxnJoin->JoinTransaction ( NULL,
|
|
ISOLATIONLEVEL_UNSPECIFIED,
|
|
0,
|
|
NULL
|
|
),S_OK))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
|
|
//AbortCoord takes care of zombied rowsets on session 1, now do it for session 2
|
|
//So close rowsets
|
|
m_pChgRowset2->ReleaseRowsetObject();
|
|
//Now recreate the rowsets
|
|
m_pChgRowset2->MakeRowset();
|
|
|
|
//Shouldn't be able to see the change
|
|
if (!COMPARE(FindChange(m_pChgRowset1), FALSE))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
//Shouldn't be able to see the change
|
|
if (!COMPARE(FindChange(m_pChgRowset2), FALSE))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
fResults = TRUE;
|
|
CLEANUP:
|
|
m_pChgRowset1->FreeJoinTxn();
|
|
m_pChgRowset2->FreeJoinTxn();
|
|
if (pITransaction)
|
|
{
|
|
m_pChgRowset1->FreeCoordTxn(pITransaction);
|
|
pITransaction = NULL;
|
|
}
|
|
ReleaseAllRowsetsAndTxns();
|
|
SAFE_RELEASE(pIRowset);
|
|
if (fResults)
|
|
return TEST_PASS;
|
|
else
|
|
return TEST_FAIL;
|
|
}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(2)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc Commit two sessions joined to a coord transactions on same DSO
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int CMultipleTxns::Variation_2()
|
|
{
|
|
BOOL fResults = FALSE;
|
|
HRESULT hr;
|
|
|
|
ITransaction *pITransaction = NULL;
|
|
IRowset *pIRowset = NULL;
|
|
|
|
//start coordinated txn & join it
|
|
if (CHECK(m_pChgRowset1->StartCoordTxn(&pITransaction,m_fIsoLevel), TRUE))
|
|
{
|
|
//get transactionjoin transaction object.
|
|
if (CHECK(m_pChgRowset1->GetTxnJoin(), S_OK))
|
|
{
|
|
if (CHECK(m_pChgRowset1->m_pITxnJoin->JoinTransaction ( pITransaction,
|
|
m_fIsoLevel,
|
|
0,
|
|
NULL
|
|
), S_OK))
|
|
{
|
|
//get 2nd transactionjoin transaction object.
|
|
if (CHECK(m_pChgRowset2->GetTxnJoin(), S_OK))
|
|
{
|
|
//join the coordinated txn from a 2nd session
|
|
if (CHECK(m_pChgRowset2->m_pITxnJoin->JoinTransaction ( pITransaction,
|
|
m_fIsoLevel,
|
|
0,
|
|
NULL
|
|
), S_OK))
|
|
{
|
|
hr=m_pChgRowset1->MakeRowset();
|
|
if (!(hr==S_OK||hr==DB_S_ERRORSOCCURRED))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
hr=m_pChgRowset2->MakeRowset();
|
|
if (!(hr==S_OK||hr==DB_S_ERRORSOCCURRED))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////
|
|
//Do something in each txn, commit it, and verify change was committed
|
|
/////////////////////////////////////////////////////////////////////
|
|
|
|
//Rowset 1
|
|
//if provider does not support IRowsetChange
|
|
if (!m_pChgRowset1->m_fChange)
|
|
{
|
|
m_ulCurrentChangeRow = GetNextRowToInsert();
|
|
if(!CHECK((m_pChgRowset1->m_pTable)->Update(m_ulCurrentChangeRow,PRIMARY,TRUE,NULL,FALSE,g_ulFirstRowInTable), S_OK))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
|
|
if(!CHECK((m_pChgRowset2->m_pTable)->Update(m_ulCurrentChangeRow,PRIMARY,TRUE,NULL,FALSE,g_ulFirstRowInTable), S_OK))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//Make a change
|
|
if(!COMPARE(Change(m_pChgRowset1), TRUE))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
//Make a change
|
|
if(!COMPARE(m_pChgRowset2->Change(m_ulCurrentDelete, m_ulCurrentInsert), TRUE))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
}
|
|
//Now commit (both sessions should be committed)
|
|
if (!CHECK(m_hr = m_pChgRowset1->CommitCoord(FALSE,pITransaction,m_pChgRowset1->m_pITxnJoin), S_OK))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
|
|
//So close rowset
|
|
m_pChgRowset2->ReleaseRowsetObject();
|
|
|
|
//need to unenlist 2nd session, CommitCoord only unenlist the session that calls it
|
|
if (!CHECK(m_pChgRowset2->m_pITxnJoin->JoinTransaction ( NULL,
|
|
m_fIsoLevel,
|
|
0,
|
|
NULL
|
|
), S_OK))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
|
|
//Now recreate the rowsets
|
|
m_pChgRowset1->MakeRowset();
|
|
m_pChgRowset2->MakeRowset();
|
|
|
|
//Sleep for a few seconds; this is to ensure that the back end has had
|
|
//time to make this update visible to other transactions which
|
|
//should see it. This is only necessary for Access, which only does
|
|
//this every few seconds.
|
|
if (m_fOnAccess)
|
|
Sleep(SLEEP_TIME); //Takes milliseconds as param
|
|
|
|
//Should be able to see the change
|
|
if (!COMPARE(FindChange(m_pChgRowset1), TRUE))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
|
|
//Rowset 2, have to figure the count manually since we
|
|
//aren't on the same table as m_pChgRowset1 anymore.
|
|
|
|
if (!COMPARE(m_pChgRowset2->FindRow(m_ulCurrentInsert, NULL), TRUE))
|
|
{
|
|
//Increment our count since we already committed the delete/insert
|
|
//but won't hit the increment before CLEANUP
|
|
m_ulCurrentInsert++;
|
|
m_ulCurrentDelete++;
|
|
goto CLEANUP;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
//Increment our count since we committed the delete/insert
|
|
m_ulCurrentInsert++;
|
|
m_ulCurrentDelete++;
|
|
|
|
fResults = TRUE;
|
|
|
|
CLEANUP:
|
|
SAFE_RELEASE(pIRowset);
|
|
m_pChgRowset1->FreeJoinTxn();
|
|
m_pChgRowset2->FreeJoinTxn();
|
|
if (pITransaction)
|
|
{
|
|
m_pChgRowset1->FreeCoordTxn(pITransaction);
|
|
pITransaction = NULL;
|
|
}
|
|
ReleaseAllRowsetsAndTxns();
|
|
|
|
if (fResults)
|
|
return TEST_PASS;
|
|
else
|
|
return TEST_FAIL;
|
|
}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(3)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc Abort two sessions joined to a coord txn on same DSO, check the 2nd after
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int CMultipleTxns::Variation_3()
|
|
{
|
|
BOOL fResults = FALSE;
|
|
HRESULT hr;
|
|
|
|
ITransaction *pITransaction = NULL;
|
|
IRowset *pIRowset = NULL;
|
|
|
|
//start coordinated txn & join it
|
|
if (CHECK(m_pChgRowset1->StartCoordTxn(&pITransaction,m_fIsoLevel), TRUE))
|
|
{
|
|
//get transactionjoin transaction object.
|
|
if (CHECK(m_pChgRowset1->GetTxnJoin(), S_OK))
|
|
{
|
|
if (CHECK(m_pChgRowset1->m_pITxnJoin->JoinTransaction ( pITransaction,
|
|
m_fIsoLevel,
|
|
0,
|
|
NULL
|
|
), S_OK))
|
|
{
|
|
//get 2nd transactionjoin transaction object.
|
|
if (CHECK(m_pChgRowset2->GetTxnJoin(), S_OK))
|
|
{
|
|
//join the coordinated txn from a 2nd session
|
|
if (CHECK(m_pChgRowset2->m_pITxnJoin->JoinTransaction ( pITransaction,
|
|
m_fIsoLevel,
|
|
0,
|
|
NULL
|
|
), S_OK))
|
|
{
|
|
hr=m_pChgRowset1->MakeRowset();
|
|
if (!(hr==S_OK||hr==DB_S_ERRORSOCCURRED))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
hr=m_pChgRowset2->MakeRowset();
|
|
if (!(hr==S_OK||hr==DB_S_ERRORSOCCURRED))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////
|
|
//Do something in each txn, abort 1, and verify change was aborted
|
|
//check 2 is then working normally
|
|
/////////////////////////////////////////////////////////////////////
|
|
|
|
//Rowset 1
|
|
//if provider does not support IRowsetChange
|
|
if (!m_pChgRowset1->m_fChange)
|
|
{
|
|
m_ulCurrentChangeRow = GetNextRowToInsert();
|
|
if(!CHECK((m_pChgRowset1->m_pTable)->Update(m_ulCurrentChangeRow,PRIMARY,TRUE,NULL,FALSE,g_ulFirstRowInTable), S_OK))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//Make a change
|
|
if(!COMPARE(Change(m_pChgRowset1), TRUE))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
}
|
|
//Now abort the whole thing
|
|
if (!CHECK(m_hr = m_pChgRowset1->AbortCoord(FALSE, pITransaction,m_pChgRowset1->m_pITxnJoin), S_OK))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
|
|
//unenlist the second session from the dead dist txn
|
|
if (!CHECK(m_pChgRowset2->m_pITxnJoin->JoinTransaction ( NULL,
|
|
ISOLATIONLEVEL_UNSPECIFIED,
|
|
0,
|
|
NULL
|
|
),S_OK))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
|
|
//Commit-AbortCoord takes care of zombied rowsets on session 1, now do it for session 2
|
|
//So close rowsets
|
|
m_pChgRowset2->ReleaseRowsetObject();
|
|
//Now recreate the rowsets
|
|
m_pChgRowset2->MakeRowset();
|
|
|
|
//Shouldn't be able to see the change
|
|
if (!COMPARE(FindChange(m_pChgRowset1), FALSE))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
|
|
//if provider does not support IRowsetChange
|
|
if (!m_pChgRowset2->m_fChange)
|
|
{
|
|
m_ulCurrentChangeRow = GetNextRowToInsert();
|
|
if(!CHECK((m_pChgRowset2->m_pTable)->Update(m_ulCurrentChangeRow,PRIMARY,TRUE,NULL,FALSE,g_ulFirstRowInTable), S_OK))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//Make a change
|
|
if(!COMPARE(Change(m_pChgRowset2), TRUE))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
}
|
|
|
|
//Should be able to see the change
|
|
if (!COMPARE(FindChange(m_pChgRowset2), TRUE))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
fResults = TRUE;
|
|
CLEANUP:
|
|
SAFE_RELEASE(pIRowset);
|
|
m_pChgRowset1->FreeJoinTxn();
|
|
m_pChgRowset2->FreeJoinTxn();
|
|
if (pITransaction)
|
|
{
|
|
m_pChgRowset1->FreeCoordTxn(pITransaction);
|
|
pITransaction = NULL;
|
|
}
|
|
ReleaseAllRowsetsAndTxns();
|
|
|
|
if (fResults)
|
|
return TEST_PASS;
|
|
else
|
|
return TEST_FAIL;
|
|
}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(4)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc Abort and Commit with multiple commands/rowsets active, same session
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int CMultipleTxns::Variation_4()
|
|
{
|
|
BOOL fResults = FALSE;
|
|
IUnknown* pIUnknown = NULL;
|
|
HRESULT hr;
|
|
|
|
ITransaction *pITransaction = NULL;
|
|
|
|
//start coordinated txn & join it
|
|
if (CHECK(m_pChgRowset1->StartCoordTxn(&pITransaction,m_fIsoLevel), TRUE))
|
|
{
|
|
//get transactionjoin transaction object.
|
|
if (CHECK(m_pChgRowset1->GetTxnJoin(), S_OK))
|
|
{
|
|
//Make first rowset
|
|
hr=m_pChgRowset1->MakeRowset();
|
|
if (!(hr==S_OK||hr==DB_S_ERRORSOCCURRED))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
|
|
if (!CHECK(m_pChgRowset1->GetSessionObject(IID_IUnknown, (IUnknown**)&pIUnknown), S_OK))
|
|
goto CLEANUP;
|
|
|
|
///////////////////////////////////////////////////////
|
|
//Create a second command/rowset on the same DB Session
|
|
///////////////////////////////////////////////////////
|
|
|
|
//First we must release original session that the second object was set with
|
|
m_pChgRowset2->ReleaseRowsetObject();
|
|
m_pChgRowset2->ReleaseCommandObject();
|
|
m_pChgRowset2->ReleaseDBSession();
|
|
if (m_pChgRowset2->m_pITxnJoin)
|
|
{
|
|
m_pChgRowset2->m_pITxnJoin->Release();
|
|
m_pChgRowset2->m_pITxnJoin = NULL;
|
|
}
|
|
|
|
//Now set session to that of our first rowset
|
|
m_pChgRowset2->SetDBSession(pIUnknown);
|
|
|
|
//Make sure we use the same table so row numbering is right --
|
|
//m_pChgRowset2 won't own this table, just use it in this variation
|
|
m_pChgRowset2->SetTable(m_pChgRowset1->m_pTable, DELETETABLE_NO);
|
|
|
|
//Make second rowset
|
|
m_pChgRowset2->SetTxnRowsetProperties();
|
|
hr=m_pChgRowset2->MakeRowset();
|
|
if (!(hr==S_OK||hr==DB_S_ERRORSOCCURRED))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
|
|
//Start Txn on our DB Session
|
|
m_hr = m_pChgRowset1->m_pITxnJoin->JoinTransaction ( pITransaction,
|
|
m_fIsoLevel,
|
|
0,
|
|
NULL
|
|
);
|
|
//Some providers such as ODBC Provider to SQL Server will not allow this
|
|
//because they can't have mutliple commands per transaction
|
|
if (m_hr == XACT_E_CONNECTION_DENIED)
|
|
{
|
|
odtLog << L"This provider does not support multiple commands in the same transaction, this is expected behavior for ODBC Provider to SQL Server. \n";
|
|
fResults = TRUE;
|
|
goto CLEANUP;
|
|
}
|
|
else
|
|
{
|
|
//Providers such as ODBC Provider to Access can't support
|
|
//starting a transaction with a rowset open
|
|
if (m_hr == E_FAIL)
|
|
{
|
|
//So close rowsets before creating txn
|
|
m_pChgRowset1->ReleaseRowsetObject();
|
|
m_pChgRowset2->ReleaseRowsetObject();
|
|
|
|
m_hr = m_pChgRowset1->m_pITxnJoin->JoinTransaction ( pITransaction,
|
|
m_fIsoLevel,
|
|
0,
|
|
NULL
|
|
);
|
|
//Now recreate the rowsets
|
|
m_pChgRowset1->MakeRowset();
|
|
m_pChgRowset2->MakeRowset();
|
|
|
|
//StartTxn should always work since rowsets were closed
|
|
if (!CHECK(m_hr, S_OK))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
if (!CHECK(m_hr, S_OK))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
}
|
|
}
|
|
///////////////////////////////////////////////////////////////
|
|
//Make changes to both rowsets and verify they both get aborted
|
|
///////////////////////////////////////////////////////////////
|
|
|
|
//if provider does not support IRowsetChange
|
|
if (!m_pChgRowset1->m_fChange)
|
|
{
|
|
m_ulCurrentChangeRow = GetNextRowToInsert();
|
|
if(!CHECK((m_pChgRowset1->m_pTable)->Update(m_ulCurrentChangeRow,PRIMARY,TRUE,NULL,FALSE,g_ulFirstRowInTable), S_OK))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if(!COMPARE(Change(m_pChgRowset1), TRUE))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
}
|
|
|
|
//Record all the txn related things that are now true about
|
|
//rowset 2 because it shares a session with rowset 1
|
|
m_pChgRowset2->CopyTxnInfo(m_pChgRowset1);
|
|
|
|
//if provider does not support IRowsetChange
|
|
if (!m_pChgRowset2->m_fChange)
|
|
{
|
|
m_ulCurrentChangeRow = GetNextRowToInsert();
|
|
if(!CHECK((m_pChgRowset2->m_pTable)->Update(m_ulCurrentChangeRow,PRIMARY,TRUE,NULL,FALSE,g_ulFirstRowInTable), S_OK))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if(!COMPARE(Change(m_pChgRowset2), TRUE))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
}
|
|
|
|
//Now abort the whole session
|
|
if (!CHECK(m_hr = m_pChgRowset1->AbortCoord(FALSE, pITransaction,m_pChgRowset1->m_pITxnJoin), S_OK))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
|
|
//Commit-AbortCoord takes care of zombied rowsets on sessin 1, now do it for session 2
|
|
//So close rowsets
|
|
m_pChgRowset2->ReleaseRowsetObject();
|
|
//Now recreate the rowsets
|
|
m_pChgRowset2->MakeRowset();
|
|
|
|
//Record all the txn related things that are now true about
|
|
//rowset 2 because it shares a session with rowset 1
|
|
m_pChgRowset2->CopyTxnInfo(m_pChgRowset1);
|
|
|
|
//Shouldn't be able to see the changes
|
|
if (!COMPARE(FindChange(m_pChgRowset1), FALSE))
|
|
goto CLEANUP;
|
|
if (!COMPARE(FindChange(m_pChgRowset2), FALSE))
|
|
goto CLEANUP;
|
|
|
|
//the coord txn was aborted-nonretaining so start a new one in order to get a valid coord txn pointer
|
|
if (pITransaction)
|
|
{
|
|
m_pChgRowset1->FreeCoordTxn(pITransaction);
|
|
pITransaction = NULL;
|
|
}
|
|
//start coordinated txn & join it
|
|
if (CHECK(m_pChgRowset1->StartCoordTxn(&pITransaction,m_fIsoLevel), TRUE))
|
|
{
|
|
//Start a new Txn since we aborted the last one non retaining
|
|
//join Txn from our DB Session, ITransactoinJoin pointer should still be valid
|
|
if (!CHECK(m_pChgRowset1->m_pITxnJoin->JoinTransaction ( pITransaction,
|
|
m_fIsoLevel,
|
|
0,
|
|
NULL
|
|
),S_OK))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////
|
|
//Make changes to both rowsets and verify they both get committed
|
|
/////////////////////////////////////////////////////////////////
|
|
|
|
//if provider does not support IRowsetChange
|
|
if (!m_pChgRowset1->m_fChange)
|
|
{
|
|
m_ulCurrentChangeRow = GetNextRowToInsert();
|
|
if(!CHECK((m_pChgRowset1->m_pTable)->Update(m_ulCurrentChangeRow,PRIMARY,TRUE,NULL,FALSE,g_ulFirstRowInTable), S_OK))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if(!COMPARE(Change(m_pChgRowset1), TRUE))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
}
|
|
|
|
//Record all the txn related things that are now true about
|
|
//rowset 2 because it shares a session with rowset 1
|
|
m_pChgRowset2->CopyTxnInfo(m_pChgRowset1);
|
|
|
|
//if provider does not support IRowsetChange
|
|
if (!m_pChgRowset2->m_fChange)
|
|
{
|
|
m_ulCurrentChangeRow = GetNextRowToInsert();
|
|
if(!CHECK((m_pChgRowset2->m_pTable)->Update(m_ulCurrentChangeRow,PRIMARY,TRUE,NULL,FALSE,g_ulFirstRowInTable), S_OK))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if(!COMPARE(Change(m_pChgRowset2), TRUE))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
}
|
|
|
|
//Now commit the whole session
|
|
if (!CHECK(m_hr = m_pChgRowset1->CommitCoord(FALSE, pITransaction,m_pChgRowset1->m_pITxnJoin), S_OK))
|
|
goto CLEANUP;
|
|
|
|
//Commit-AbortCoord takes care of zombied rowsets on sessin 1, now do it for session 2
|
|
//So close rowsets
|
|
m_pChgRowset2->ReleaseRowsetObject();
|
|
//Now recreate the rowsets
|
|
m_pChgRowset2->MakeRowset();
|
|
|
|
//Sleep for a few seconds; this is to ensure that the back end has had
|
|
//time to make this update visible to other transactions which
|
|
//should see it. This is only necessary for Access, which only does
|
|
//this every few seconds.
|
|
if (m_fOnAccess)
|
|
Sleep(SLEEP_TIME); //Takes milliseconds as param
|
|
|
|
//Since we are sharing one session for the commit of two updates, and that
|
|
//commit only assumes there is one change per commit, increment
|
|
//our count for the second update on the same table
|
|
//g_ulLastActualDelete++;
|
|
//g_ulLastActualInsert;
|
|
g_DeleteAndInsertIncrement();
|
|
|
|
//Record all the txn related things that are now true about
|
|
//rowset 2 because it shares a session with rowset 1
|
|
m_pChgRowset2->CopyTxnInfo(m_pChgRowset1);
|
|
|
|
//Should be able to see the changes
|
|
if (!COMPARE(FindChange(m_pChgRowset1), TRUE))
|
|
goto CLEANUP;
|
|
if (!COMPARE(FindChange(m_pChgRowset2), TRUE))
|
|
goto CLEANUP;
|
|
}
|
|
}
|
|
}
|
|
fResults = TRUE;
|
|
CLEANUP:
|
|
m_pChgRowset1->FreeJoinTxn();
|
|
if (pITransaction)
|
|
{
|
|
m_pChgRowset1->FreeCoordTxn(pITransaction);
|
|
pITransaction = NULL;
|
|
}
|
|
if(pIUnknown)
|
|
pIUnknown->Release();
|
|
|
|
//Give m_pChgRowset2 back the ownership of the table it got
|
|
//in Init() so that it will clean it up in it's destructor
|
|
m_pChgRowset2->SetTable(m_pTable, DELETETABLE_YES);
|
|
ReleaseAllRowsetsAndTxns();
|
|
|
|
if (fResults)
|
|
return TEST_PASS;
|
|
else
|
|
return TEST_FAIL;
|
|
}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(5)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc Multiple Sessions, only one joins the coord Transaction
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int CMultipleTxns::Variation_5()
|
|
{
|
|
BOOL fResults = FALSE;
|
|
IUnknown *pIUnknown = NULL;
|
|
ULONG cPropSets = 0;
|
|
DBPROPSET *rgPropSets = NULL;
|
|
HRESULT hr;
|
|
|
|
ITransaction *pITransaction = NULL;
|
|
IRowset *pIRowset = NULL;
|
|
|
|
//Make first rowset
|
|
hr=m_pChgRowset1->MakeRowset();
|
|
if (!(hr==S_OK||hr==DB_S_ERRORSOCCURRED))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////
|
|
//Create a second command/rowset on a different DB Session
|
|
///////////////////////////////////////////////////////
|
|
|
|
//Clean up all objects existing
|
|
m_pChgRowset2->Terminate();
|
|
|
|
//Make a new session
|
|
if (!COMPARE(m_pChgRowset2->Init(), TRUE))
|
|
goto CLEANUP;
|
|
|
|
//Set the second different table back into m_pChgRowset2
|
|
//since the call to m_pChgRowset2->Terminate wiped it out
|
|
m_pChgRowset2->SetTable(m_pTable, DELETETABLE_YES);
|
|
|
|
//start coordinated txn & join it
|
|
if (CHECK(m_pChgRowset1->StartCoordTxn(&pITransaction,m_fIsoLevel), TRUE))
|
|
{
|
|
//get 2nd transactionjoin transaction(session) object.
|
|
if (CHECK(m_pChgRowset2->GetTxnJoin(), S_OK))
|
|
{
|
|
//join the coordinated txn from a 2nd session
|
|
if (CHECK(m_pChgRowset2->m_pITxnJoin->JoinTransaction ( pITransaction,
|
|
m_fIsoLevel,
|
|
0,
|
|
NULL
|
|
), S_OK))
|
|
{
|
|
hr=m_pChgRowset2->MakeRowset();
|
|
if (!(hr==S_OK||hr==DB_S_ERRORSOCCURRED))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////
|
|
//Make changes to both rowsets and verify only one gets aborted
|
|
///////////////////////////////////////////////////////////////
|
|
|
|
//if provider does not support IRowsetChange
|
|
if (!m_pChgRowset1->m_fChange)
|
|
{
|
|
m_ulCurrentChangeRow = GetNextRowToInsert();
|
|
if(!CHECK((m_pChgRowset1->m_pTable)->Update(m_ulCurrentChangeRow,PRIMARY,TRUE,NULL,FALSE,g_ulFirstRowInTable), S_OK))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
|
|
if(!CHECK((m_pChgRowset2->m_pTable)->Update(m_ulCurrentChangeRow,PRIMARY,TRUE,NULL,FALSE,g_ulFirstRowInTable), S_OK))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if(!COMPARE(Change(m_pChgRowset1), TRUE))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
if(!COMPARE(m_pChgRowset2->Change(m_ulCurrentDelete, m_ulCurrentInsert), TRUE))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
}
|
|
|
|
|
|
//Now abort the coord txn
|
|
if (!CHECK(m_hr = m_pChgRowset2->AbortCoord(FALSE, pITransaction,m_pChgRowset2->m_pITxnJoin), S_OK))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
|
|
//Shouldn't be able to see the changes here
|
|
if (!COMPARE(m_pChgRowset2->FindRow(m_ulCurrentInsert, NULL), FALSE))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
|
|
//But should be able to see them on non transacted rowset
|
|
//Note that we don't want to use FindChange() here because
|
|
//that looks for the last changed row, which would have
|
|
//been incremented for the second change we did, and
|
|
//we want the first change we did (the one that actually
|
|
//wasn't aborted).
|
|
if (!COMPARE(m_pChgRowset1->FindRow(g_ulLastActualInsert, NULL), TRUE))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
fResults = TRUE;
|
|
CLEANUP:
|
|
m_pChgRowset2->FreeJoinTxn();
|
|
if (pITransaction)
|
|
{
|
|
m_pChgRowset1->FreeCoordTxn(pITransaction);
|
|
pITransaction = NULL;
|
|
}
|
|
ReleaseAllRowsetsAndTxns();
|
|
|
|
if (fResults)
|
|
return TEST_PASS;
|
|
else
|
|
return TEST_FAIL;
|
|
}
|
|
// {{ TCW_VAR_PROTOTYPE(6)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc Abort and Commit from 2 session, each to it's own coord txn
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int CMultipleTxns::Variation_6()
|
|
{
|
|
BOOL fResults = FALSE;
|
|
IUnknown* pIUnknown = NULL;
|
|
HRESULT hr;
|
|
|
|
ITransaction *pITransaction1 = NULL;
|
|
ITransaction *pITransaction2 = NULL;
|
|
|
|
if(gfBlocked)
|
|
{
|
|
return TEST_SKIPPED;
|
|
}
|
|
//start coordinated txn & join it
|
|
if (CHECK(m_pChgRowset1->StartCoordTxn(&pITransaction1,m_fIsoLevel), TRUE))
|
|
{
|
|
if (CHECK(m_pChgRowset1->StartCoordTxn(&pITransaction2,m_fIsoLevel), TRUE))
|
|
{
|
|
//get transactionjoin transaction object.
|
|
if (CHECK(m_pChgRowset1->GetTxnJoin(), S_OK))
|
|
{
|
|
if(!CHECK(m_pChgRowset1->m_pITxnJoin->JoinTransaction ( pITransaction1,
|
|
m_fIsoLevel,
|
|
0,
|
|
NULL
|
|
),S_OK))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
//can't have same session joined to 2 different global(coord) txns
|
|
if(!CHECK(m_pChgRowset1->m_pITxnJoin->JoinTransaction ( pITransaction2,
|
|
m_fIsoLevel,
|
|
0,
|
|
NULL
|
|
),XACT_E_XTIONEXISTS))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
//get 2nd transactionjoin transaction object.
|
|
if (CHECK(m_pChgRowset2->GetTxnJoin(), S_OK))
|
|
{
|
|
if(CHECK(m_pChgRowset2->m_pITxnJoin->JoinTransaction ( pITransaction2,
|
|
m_fIsoLevel,
|
|
0,
|
|
NULL
|
|
),S_OK))
|
|
{
|
|
hr=m_pChgRowset1->MakeRowset();
|
|
if (!(hr==S_OK||hr==DB_S_ERRORSOCCURRED))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
hr=m_pChgRowset2->MakeRowset();
|
|
if (!(hr==S_OK||hr==DB_S_ERRORSOCCURRED))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////
|
|
//Do something in each txn, abort 1, and verify change was aborted
|
|
//check 2 is then working normally
|
|
/////////////////////////////////////////////////////////////////////
|
|
//Rowset 1
|
|
//if provider does not support IRowsetChange
|
|
if (!m_pChgRowset1->m_fChange)
|
|
{
|
|
m_ulCurrentChangeRow = GetNextRowToInsert();
|
|
if(!CHECK((m_pChgRowset1->m_pTable)->Update(m_ulCurrentChangeRow,PRIMARY,TRUE,NULL,FALSE,g_ulFirstRowInTable), S_OK))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
|
|
if(!CHECK((m_pChgRowset2->m_pTable)->Update(m_ulCurrentChangeRow,PRIMARY,TRUE,NULL,FALSE,g_ulFirstRowInTable), S_OK))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//Make a change 1st session
|
|
if(!COMPARE(Change(m_pChgRowset1), TRUE))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
//Make a change, 2nd session
|
|
if(!COMPARE(m_pChgRowset2->Change(m_ulCurrentDelete, m_ulCurrentInsert), TRUE))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
}
|
|
//Now abort the whole thing (1 session)
|
|
if (!CHECK(m_hr = m_pChgRowset1->AbortCoord(FALSE, pITransaction1,m_pChgRowset1->m_pITxnJoin), S_OK))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
|
|
//no txn, abort should fail
|
|
m_hr = m_pChgRowset1->AbortCoord(FALSE, pITransaction1,m_pChgRowset1->m_pITxnJoin);
|
|
if (XACT_E_NOTRANSACTION!= m_hr)
|
|
{
|
|
COMPARE(1,0);
|
|
goto CLEANUP;
|
|
}
|
|
//no txn, commit should fail
|
|
m_hr = m_pChgRowset1->CommitCoord(FALSE, pITransaction1,m_pChgRowset1->m_pITxnJoin);
|
|
if (XACT_E_NOTRANSACTION!= m_hr)
|
|
{
|
|
COMPARE(1,0);
|
|
goto CLEANUP;
|
|
}
|
|
//Now commit the whole thing (1 session)
|
|
if (!CHECK(m_hr = m_pChgRowset2->CommitCoord(FALSE, pITransaction2,m_pChgRowset2->m_pITxnJoin), S_OK))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
//no txn, abort should fail
|
|
m_hr = m_pChgRowset2->AbortCoord(FALSE, pITransaction2,m_pChgRowset2->m_pITxnJoin);
|
|
if (XACT_E_NOTRANSACTION!= m_hr)
|
|
{
|
|
COMPARE(1,0);
|
|
goto CLEANUP;
|
|
}
|
|
//no txn, commit should fail
|
|
m_hr = m_pChgRowset2->CommitCoord(FALSE, pITransaction2,m_pChgRowset2->m_pITxnJoin);
|
|
if (XACT_E_NOTRANSACTION!= m_hr)
|
|
{
|
|
COMPARE(1,0);
|
|
goto CLEANUP;
|
|
}
|
|
|
|
//Commit-AbortCoord takes care of zombied rowsets on sessin 1, now do it for session 2
|
|
//So close rowsets
|
|
m_pChgRowset2->ReleaseRowsetObject();
|
|
//Now recreate the rowsets
|
|
m_pChgRowset2->MakeRowset();
|
|
|
|
//Shouldn't be able to see the change
|
|
if (!COMPARE(FindChange(m_pChgRowset1), FALSE))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
//Should be able to see the change
|
|
if (!COMPARE(FindChange(m_pChgRowset2), TRUE))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
fResults = TRUE;
|
|
CLEANUP:
|
|
m_pChgRowset1->FreeJoinTxn();
|
|
if (pITransaction1)
|
|
{
|
|
m_pChgRowset1->FreeCoordTxn(pITransaction1);
|
|
pITransaction1 = NULL;
|
|
}
|
|
m_pChgRowset2->FreeJoinTxn();
|
|
if (pITransaction2)
|
|
{
|
|
m_pChgRowset2->FreeCoordTxn(pITransaction2);
|
|
pITransaction2 = NULL;
|
|
}
|
|
ReleaseAllRowsetsAndTxns();
|
|
|
|
if (fResults)
|
|
return TEST_PASS;
|
|
else
|
|
return TEST_FAIL;
|
|
}
|
|
// }}
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(7)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc two sessions, UnEnlist from one
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int CMultipleTxns::Variation_7()
|
|
{
|
|
BOOL fResults = FALSE;
|
|
HRESULT hr;
|
|
|
|
ITransaction *pITransaction = NULL;
|
|
IRowset *pIRowset = NULL;
|
|
|
|
for (ULONG i=0;i<100;i++)
|
|
{
|
|
//start coordinated txn & join it
|
|
if (CHECK(m_pChgRowset1->StartCoordTxn(&pITransaction,m_fIsoLevel), TRUE))
|
|
{
|
|
//get transactionjoin transaction object.
|
|
if (CHECK(m_pChgRowset1->GetTxnJoin(), S_OK))
|
|
{
|
|
if (CHECK(m_pChgRowset1->m_pITxnJoin->JoinTransaction ( pITransaction,
|
|
m_fIsoLevel,
|
|
0,
|
|
NULL
|
|
), S_OK))
|
|
{
|
|
//get 2nd transactionjoin transaction object.
|
|
if (CHECK(m_pChgRowset2->GetTxnJoin(), S_OK))
|
|
{
|
|
//join the coordinated txn from a 2nd session
|
|
if (CHECK(m_pChgRowset2->m_pITxnJoin->JoinTransaction ( pITransaction,
|
|
m_fIsoLevel,
|
|
0,
|
|
NULL
|
|
), S_OK))
|
|
{
|
|
//OpenRowset in each session
|
|
hr=m_pChgRowset1->MakeRowset();
|
|
if (!(hr==S_OK||hr==DB_S_ERRORSOCCURRED))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
hr=m_pChgRowset2->MakeRowset();
|
|
if (!(hr==S_OK||hr==DB_S_ERRORSOCCURRED))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
|
|
//commit the global txn (both sessin get committed)
|
|
if (!CHECK(pITransaction->Commit( FALSE,
|
|
XACTTC_ASYNC_PHASEONE,
|
|
0),XACT_S_ASYNC))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
|
|
//close both rowsets
|
|
m_pChgRowset1->ReleaseRowsetObject();
|
|
m_pChgRowset2->ReleaseRowsetObject();
|
|
|
|
//UnEnlist one session
|
|
if (!CHECK(m_pChgRowset1->m_pITxnJoin->JoinTransaction ( NULL,
|
|
m_fIsoLevel,
|
|
0,
|
|
NULL
|
|
), S_OK))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
//UnEnlist the other session
|
|
if (!CHECK(m_pChgRowset2->m_pITxnJoin->JoinTransaction ( NULL,
|
|
m_fIsoLevel,
|
|
0,
|
|
NULL
|
|
), S_OK))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
m_pChgRowset1->FreeJoinTxn();
|
|
m_pChgRowset2->FreeJoinTxn();
|
|
if (pITransaction)
|
|
{
|
|
m_pChgRowset1->FreeCoordTxn(pITransaction);
|
|
pITransaction = NULL;
|
|
}
|
|
}
|
|
fResults = TRUE;
|
|
CLEANUP:
|
|
m_pChgRowset1->FreeJoinTxn();
|
|
// m_pChgRowset2->FreeJoinTxn();
|
|
if (pITransaction)
|
|
{
|
|
m_pChgRowset1->FreeCoordTxn(pITransaction);
|
|
pITransaction = NULL;
|
|
}
|
|
ReleaseAllRowsetsAndTxns();
|
|
SAFE_RELEASE(pIRowset);
|
|
if (fResults)
|
|
return TEST_PASS;
|
|
else
|
|
return TEST_FAIL;
|
|
}
|
|
// }}
|
|
// }}
|
|
// {{ TCW_TERMINATE_METHOD
|
|
//--------------------------------------------------------------------
|
|
// @mfunc TestCase Termination Routine
|
|
//
|
|
// @rdesc TRUE or FALSE
|
|
//
|
|
BOOL CMultipleTxns::Terminate()
|
|
{
|
|
if (!m_fOnAccess)
|
|
{
|
|
ReleaseDBSession();
|
|
}
|
|
// {{ TCW_TERM_BASECLASS_CHECK2
|
|
return(CTxnImmed::Terminate());
|
|
} // }}
|
|
// }}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_TC_PROTOTYPE(CSequence)
|
|
//*-----------------------------------------------------------------------
|
|
//| Test Case: CSequence - Sequence testing for StartTransaction and ITransactionOptions
|
|
//| Created: 05/17/96
|
|
//*-----------------------------------------------------------------------
|
|
//--------------------------------------------------------------------
|
|
// @mfunc Start DTC, coordinated transaction
|
|
//
|
|
// @rdesc TRUE or FALSE
|
|
//
|
|
BOOL CSequence::StartCoordTxn( ITransaction **ppITransaction,
|
|
ISOLEVEL isolevel)
|
|
{
|
|
ITransactionDispenser *pTransactionDispenser = NULL;
|
|
HRESULT hr;
|
|
|
|
if(ppITransaction)
|
|
{
|
|
*ppITransaction = NULL;
|
|
}
|
|
|
|
// Obtain the ITransactionDispenser Interface pointer
|
|
// by calling DtcGetTransactionManager()
|
|
hr = DtcGetTransactionManager(
|
|
NULL, // LPTSTR pszHost,
|
|
NULL, // LPTSTR pszTmName,
|
|
IID_ITransactionDispenser, // /* in */ REFIID rid,
|
|
0, // /* in */ DWORD dwReserved1,
|
|
0, // /* in */ WORD wcbReserved2,
|
|
NULL, // /* in */ void FAR * pvReserved2,
|
|
(void**)&pTransactionDispenser // /* out */ void** ppvObject
|
|
);
|
|
if (FAILED (hr))
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
hr = pTransactionDispenser->BeginTransaction(
|
|
NULL, // /* [in] */ IUnknown __RPC_FAR *punkOuter,
|
|
isolevel, // /* [in] */ ISOLEVEL isoLevel,
|
|
0, // /* [in] */ ULONG isoFlags,
|
|
NULL, // /* [in] */ ITransactionOptions *pOptions
|
|
(ITransaction**)ppITransaction // /* [out] */ ITransaction **ppTransaction
|
|
);
|
|
|
|
SAFE_RELEASE(pTransactionDispenser);
|
|
|
|
if (FAILED (hr))
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
///--------------------------------------------------------------------
|
|
// get TxnJoin
|
|
// @mfunc Abort
|
|
//--------------------------------------------------------------------
|
|
HRESULT CSequence::GetTxnJoin() // @parm [OUT] Session Pointer)
|
|
{
|
|
if(m_pITxnJoin)
|
|
m_pITxnJoin = NULL;
|
|
|
|
if(m_pIOpenRowset)
|
|
{
|
|
if(!VerifyInterface(m_pIOpenRowset, IID_ITransactionJoin, SESSION_INTERFACE, (IUnknown**)&m_pITxnJoin))
|
|
return E_NOINTERFACE;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
return E_FAIL;
|
|
}
|
|
|
|
//--------------------------------------------------------------------
|
|
// Free Txn Join object
|
|
// @mfunc
|
|
//--------------------------------------------------------------------
|
|
BOOL CSequence::FreeJoinTxn()
|
|
{
|
|
SAFE_RELEASE(m_pITxnJoin);
|
|
return TRUE;
|
|
}
|
|
|
|
//--------------------------------------------------------------------
|
|
// Free Coordinated Txn object
|
|
// @mfunc
|
|
//--------------------------------------------------------------------
|
|
BOOL CSequence::FreeCoordTxn(ITransaction *pITransaction)
|
|
{
|
|
//end any open transaction
|
|
pITransaction->Abort(NULL,FALSE,FALSE);
|
|
SAFE_RELEASE(pITransaction);
|
|
return TRUE;
|
|
}
|
|
|
|
//--------------------------------------------------------------------
|
|
// @mfunc TestCase Initialization Routine
|
|
//
|
|
// @rdesc TRUE or FALSE
|
|
//
|
|
BOOL CSequence::Init()
|
|
{
|
|
// {{ TCW_INIT_BASECLASS_CHECK
|
|
if(CTxn::Init())
|
|
// }}
|
|
{ //the jet engine (access) does not support distributed transactions
|
|
if (m_fOnAccess)
|
|
{
|
|
return TEST_SKIPPED;
|
|
}
|
|
else
|
|
{
|
|
if (CHECK(CreateDBSession(), S_OK))
|
|
{
|
|
return TRUE;
|
|
}
|
|
}
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(1)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc GetOptionsObject before StartTransaction
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int CSequence::Variation_1()
|
|
{
|
|
BOOL fResults = FALSE;
|
|
|
|
//start coordinated txn & join it
|
|
if (CHECK(StartCoordTxn(&m_pITransaction,m_fIsoLevel), TRUE))
|
|
{
|
|
//get transactionjoin transaction object.
|
|
if (CHECK(GetTxnJoin(), S_OK))
|
|
{
|
|
if (CHECK(m_pITxnJoin->JoinTransaction ( m_pITransaction,
|
|
m_fIsoLevel,
|
|
0,
|
|
NULL
|
|
), S_OK))
|
|
{
|
|
if (CHECK(m_pITxnJoin->GetOptionsObject(&m_pITxnOptions), S_OK))
|
|
{
|
|
if (CHECK(m_pITxnOptions->GetOptions(&m_TxnOptions), S_OK))
|
|
{
|
|
COMPARE(m_TxnOptions.ulTimeout, 0);
|
|
COMPARE(m_TxnOptions.szDescription[0], '\0');
|
|
|
|
//Now try setting them to something new
|
|
m_TxnOptions.ulTimeout = 1;
|
|
strcpy((CHAR *)m_TxnOptions.szDescription, szDESCRIPTION);
|
|
|
|
//Set should also work
|
|
if (CHECK(m_pITxnOptions->SetOptions(&m_TxnOptions), S_OK))
|
|
{
|
|
//End Txn and start again
|
|
CHECK(m_pITransaction->Commit(FALSE, 0, 0), S_OK);
|
|
if (m_pITransaction)
|
|
{
|
|
FreeCoordTxn(m_pITransaction);
|
|
m_pITransaction = NULL;
|
|
}
|
|
//unenlist the session from the dead dist txn
|
|
if (!CHECK(m_pITxnJoin->JoinTransaction ( NULL,
|
|
ISOLATIONLEVEL_UNSPECIFIED,
|
|
0,
|
|
NULL
|
|
),S_OK))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
//start coordinated txn & join it
|
|
if (CHECK(StartCoordTxn(&m_pITransaction,m_fIsoLevel), TRUE))
|
|
{
|
|
//get transactionjoin transaction object.
|
|
if (CHECK(GetTxnJoin(), S_OK))
|
|
{
|
|
//start coordinated txn & join it
|
|
if (CHECK(StartCoordTxn(&m_pITransaction,m_fIsoLevel), TRUE))
|
|
{
|
|
m_hr = m_pITxnJoin->JoinTransaction ( m_pITransaction,
|
|
m_fIsoLevel,
|
|
0,
|
|
m_pITxnOptions
|
|
);
|
|
|
|
//Do Get one more time, this time while txn is active
|
|
if (CHECK(m_pITxnOptions->GetOptions(&m_TxnOptions), S_OK))
|
|
{
|
|
//Should now have new values
|
|
COMPARE(m_TxnOptions.ulTimeout, 1);
|
|
COMPARE(strcmp((CHAR *)m_TxnOptions.szDescription, szDESCRIPTION), 0);
|
|
}
|
|
//Either of these is acceptable for JoinTransaction
|
|
if (m_hr == S_OK)
|
|
{
|
|
//Clean up txn
|
|
CHECK(m_pITransaction->Commit(FALSE, 0, 0), S_OK);
|
|
fResults = TRUE;
|
|
}
|
|
else
|
|
{
|
|
//This is OK, too
|
|
if (m_hr == XACT_E_NOTIMEOUT)
|
|
{
|
|
fResults = TRUE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if(m_pITxnOptions){m_pITxnOptions->Release();}
|
|
m_pITxnOptions = NULL;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
CLEANUP:
|
|
FreeJoinTxn();
|
|
if (m_pITransaction)
|
|
{
|
|
FreeCoordTxn(m_pITransaction);
|
|
m_pITransaction = NULL;
|
|
}
|
|
if (fResults)
|
|
return TEST_PASS;
|
|
else
|
|
return TEST_FAIL;
|
|
}
|
|
|
|
// }}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(2)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc GetOptionsObject after StartTransaction
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int CSequence::Variation_2()
|
|
{
|
|
BOOL fResults = FALSE;
|
|
|
|
//start coordinated txn & join it
|
|
if (CHECK(StartCoordTxn(&m_pITransaction,m_fIsoLevel), TRUE))
|
|
{
|
|
//get transactionjoin transaction object.
|
|
if (CHECK(GetTxnJoin(), S_OK))
|
|
{
|
|
if (CHECK(m_pITxnJoin->JoinTransaction ( m_pITransaction,
|
|
m_fIsoLevel,
|
|
0,
|
|
NULL
|
|
), S_OK))
|
|
{
|
|
if (CHECK(m_pITxnJoin->GetOptionsObject(&m_pITxnOptions), S_OK))
|
|
{
|
|
if (CHECK(m_pITxnOptions->GetOptions(&m_TxnOptions), S_OK))
|
|
{
|
|
//Now try setting them to something new
|
|
m_TxnOptions.ulTimeout = TIMEOUT;
|
|
strcpy((CHAR *)m_TxnOptions.szDescription, szDESCRIPTION);
|
|
|
|
//Set should also work
|
|
if (CHECK(m_pITxnOptions->SetOptions(&m_TxnOptions), S_OK))
|
|
{
|
|
//End Txn and start again
|
|
CHECK(m_pITransaction->Commit(FALSE, 0, 0), S_OK);
|
|
if (m_pITransaction)
|
|
{
|
|
FreeCoordTxn(m_pITransaction);
|
|
m_pITransaction = NULL;
|
|
}
|
|
//unenlist the session from the dead dist txn
|
|
if (!CHECK(m_pITxnJoin->JoinTransaction ( NULL,
|
|
ISOLATIONLEVEL_UNSPECIFIED,
|
|
0,
|
|
NULL
|
|
),S_OK))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
//start coordinated txn & join it
|
|
if (CHECK(StartCoordTxn(&m_pITransaction,m_fIsoLevel), TRUE))
|
|
{
|
|
//get transactionjoin transaction object.
|
|
if (CHECK(GetTxnJoin(), S_OK))
|
|
{
|
|
m_hr=m_pITxnJoin->JoinTransaction ( m_pITransaction,
|
|
m_fIsoLevel,
|
|
0,
|
|
m_pITxnOptions
|
|
);
|
|
{
|
|
//Either of these is acceptable
|
|
if (m_hr == S_OK)
|
|
{
|
|
//Clean up txn
|
|
CHECK(m_pITransaction->Commit(FALSE, 0, 0), S_OK);
|
|
fResults = TRUE;
|
|
}
|
|
else
|
|
{
|
|
//This is OK, too
|
|
if (m_hr == XACT_E_NOTIMEOUT)
|
|
{
|
|
fResults = TRUE;
|
|
}
|
|
}
|
|
|
|
//Do Get one more time
|
|
if (CHECK(m_pITxnOptions->GetOptions(&m_TxnOptions), S_OK))
|
|
{
|
|
//Should now have new values
|
|
COMPARE(m_TxnOptions.ulTimeout, TIMEOUT);
|
|
COMPARE(strcmp((CHAR *)m_TxnOptions.szDescription, szDESCRIPTION), 0);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
CHECK(m_pITransaction->Commit(FALSE, 0, 0), S_OK);
|
|
}
|
|
}
|
|
if(m_pITxnOptions){m_pITxnOptions->Release();}
|
|
m_pITxnOptions = NULL;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
CLEANUP:
|
|
FreeJoinTxn();
|
|
if (m_pITransaction)
|
|
{
|
|
FreeCoordTxn(m_pITransaction);
|
|
m_pITransaction = NULL;
|
|
}
|
|
|
|
if (fResults)
|
|
return TEST_PASS;
|
|
else
|
|
return TEST_FAIL;
|
|
}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(3)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc SetOptions twice
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int CSequence::Variation_3()
|
|
{
|
|
BOOL fResults = FALSE;
|
|
|
|
//start coordinated txn & join it
|
|
if (CHECK(StartCoordTxn(&m_pITransaction,m_fIsoLevel), TRUE))
|
|
{
|
|
//get transactionjoin transaction object.
|
|
if (CHECK(GetTxnJoin(), S_OK))
|
|
{
|
|
if (CHECK(m_pITxnJoin->JoinTransaction ( m_pITransaction,
|
|
m_fIsoLevel,
|
|
0,
|
|
NULL
|
|
), S_OK))
|
|
{
|
|
if (CHECK(m_pITxnJoin->GetOptionsObject(&m_pITxnOptions), S_OK))
|
|
{
|
|
//Set options
|
|
m_TxnOptions.ulTimeout = TIMEOUT;
|
|
strcpy((CHAR *)m_TxnOptions.szDescription, szDESCRIPTION);
|
|
|
|
if (CHECK(m_pITxnOptions->SetOptions(&m_TxnOptions), S_OK))
|
|
{
|
|
//Now try setting them to something new
|
|
m_TxnOptions.ulTimeout = 0;
|
|
m_TxnOptions.szDescription[0] = '\0';
|
|
|
|
if (CHECK(m_pITxnOptions->SetOptions(&m_TxnOptions), S_OK))
|
|
{
|
|
if (CHECK(m_pITxnOptions->GetOptions(&m_TxnOptions), S_OK))
|
|
{
|
|
//Should now have latest values
|
|
COMPARE(m_TxnOptions.ulTimeout, 0);
|
|
COMPARE(strcmp((CHAR *)m_TxnOptions.szDescription, ""), 0);
|
|
}
|
|
}
|
|
|
|
//End Txn and start again
|
|
CHECK(m_pITransaction->Commit(FALSE, 0, 0), S_OK);
|
|
if (m_pITransaction)
|
|
{
|
|
FreeCoordTxn(m_pITransaction);
|
|
m_pITransaction = NULL;
|
|
}
|
|
//unenlist the session from the dead dist txn
|
|
if (!CHECK(m_pITxnJoin->JoinTransaction ( NULL,
|
|
ISOLATIONLEVEL_UNSPECIFIED,
|
|
0,
|
|
NULL
|
|
),S_OK))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
|
|
//start coordinated txn & join it
|
|
if (CHECK(StartCoordTxn(&m_pITransaction,m_fIsoLevel), TRUE))
|
|
{
|
|
//get transactionjoin transaction object.
|
|
if (CHECK(GetTxnJoin(), S_OK))
|
|
{
|
|
m_hr=m_pITxnJoin->JoinTransaction ( m_pITransaction,
|
|
m_fIsoLevel,
|
|
0,
|
|
m_pITxnOptions
|
|
);
|
|
//Either of these is acceptable
|
|
if (m_hr == S_OK)
|
|
{
|
|
//Clean up txn
|
|
CHECK(m_pITransaction->Commit(FALSE, 0, 0), S_OK);
|
|
fResults = TRUE;
|
|
}
|
|
else
|
|
{
|
|
//This is OK, too
|
|
if (m_hr == XACT_E_NOTIMEOUT)
|
|
{
|
|
fResults = TRUE;
|
|
}
|
|
//Do Get one more time
|
|
if (CHECK(m_pITxnOptions->GetOptions(&m_TxnOptions), S_OK))
|
|
{
|
|
//Should now have new values
|
|
COMPARE(m_TxnOptions.ulTimeout, TIMEOUT);
|
|
COMPARE(strcmp((CHAR *)m_TxnOptions.szDescription, szDESCRIPTION), 0);
|
|
}
|
|
}
|
|
}
|
|
if(m_pITxnOptions){m_pITxnOptions->Release();}
|
|
m_pITxnOptions = NULL;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
CLEANUP:
|
|
FreeJoinTxn();
|
|
if (m_pITransaction)
|
|
{
|
|
FreeCoordTxn(m_pITransaction);
|
|
m_pITransaction = NULL;
|
|
}
|
|
|
|
if (fResults)
|
|
return TEST_PASS;
|
|
else
|
|
return TEST_FAIL;
|
|
}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_TERMINATE_METHOD
|
|
//--------------------------------------------------------------------
|
|
// @mfunc TestCase Termination Routine
|
|
//
|
|
// @rdesc TRUE or FALSE
|
|
//
|
|
BOOL CSequence::Terminate()
|
|
{
|
|
if (!m_fOnAccess)
|
|
{
|
|
ReleaseDBSession();
|
|
SAFE_RELEASE(m_pITxnJoin);
|
|
SAFE_RELEASE(m_pITransaction);
|
|
}
|
|
|
|
// {{ TCW_TERM_BASECLASS_CHECK2
|
|
return(CTxn::Terminate());
|
|
} // }}
|
|
// }}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_TC_PROTOTYPE(TCExtendedErrors)
|
|
//*-----------------------------------------------------------------------
|
|
//| Test Case: TCExtendedErrors - Extended Errors
|
|
//| Created: 07/31/96
|
|
//*-----------------------------------------------------------------------
|
|
|
|
//--------------------------------------------------------------------
|
|
// @mfunc TestCase Initialization Routine
|
|
//
|
|
// @rdesc TRUE or FALSE
|
|
//
|
|
BOOL TCExtendedErrors::Init()
|
|
{
|
|
BOOL fResults = FALSE;
|
|
|
|
m_pITxnOptions = NULL;
|
|
// {{ TCW_INIT_BASECLASS_CHECK
|
|
if(CTxnImmed::Init())
|
|
{
|
|
//}}
|
|
//the jet engine (access) does not support distributed transactions
|
|
if (m_fOnAccess)
|
|
{
|
|
return TEST_SKIPPED;
|
|
}
|
|
else
|
|
{
|
|
//get transactionjoin transaction object.
|
|
if (CHECK(m_pChgRowset1->GetTxnJoin(), S_OK))
|
|
{
|
|
if (CHECK(m_pChgRowset1->m_pITxnJoin->GetOptionsObject(&m_pITxnOptions),S_OK))
|
|
{
|
|
fResults = TRUE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
//free objects;
|
|
m_pChgRowset1->FreeJoinTxn();
|
|
fResults = TRUE;
|
|
return fResults;
|
|
}
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(1)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc Valid ITransactionJoin calls with previous error object existing.
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCExtendedErrors::Variation_1()
|
|
{
|
|
ULONG ulTxnLvl1 = 0;
|
|
ULONG ulTxnLvl2 = 0;
|
|
BOOL fResults = FALSE;
|
|
ITransactionOptions *pITxnOptions = NULL;
|
|
XACTTRANSINFO TxnInfo;
|
|
ITransaction *pITransaction = NULL;
|
|
|
|
|
|
//For each method of the interface, first create an error object on
|
|
//the current thread, then try get S_OK from the ITransactionJoin method.
|
|
//We then check extended errors to verify nothing is set since an
|
|
//error object shouldn't exist following a successful call.
|
|
|
|
//start coordinated txn & join it
|
|
if (CHECK(m_pChgRowset1->StartCoordTxn(&pITransaction,m_fIsoLevel), TRUE))
|
|
{
|
|
//get transactionjoin transaction object.
|
|
if (CHECK(m_pChgRowset1->GetTxnJoin(), S_OK))
|
|
{
|
|
//enlist in coordinated txn
|
|
if (CHECK(m_pChgRowset1->m_pITxnJoin->JoinTransaction ( pITransaction,
|
|
m_fIsoLevel,
|
|
0,
|
|
NULL
|
|
), S_OK))
|
|
{
|
|
//create an error object
|
|
m_pExtError->CauseError();
|
|
|
|
//Try to get the txn options interface
|
|
if (CHECK(m_hr=m_pChgRowset1->m_pITxnJoin->GetOptionsObject(&pITxnOptions),S_OK))
|
|
{
|
|
//Do extended check following GetOptionsObject
|
|
fResults = XCHECK(m_pChgRowset1->m_pITxnJoin, IID_ITransactionJoin, m_hr);
|
|
}
|
|
//create an error object
|
|
m_pExtError->CauseError();
|
|
|
|
//call GeTransactionInfo
|
|
if (CHECK(m_hr=pITransaction->GetTransactionInfo(&TxnInfo), S_OK))
|
|
{
|
|
//Do extended check following GetTransactionInfo
|
|
fResults &= XCHECK(pITransaction, IID_ITransaction, m_hr);
|
|
}
|
|
|
|
//create an error object
|
|
m_pExtError->CauseError();
|
|
|
|
//End the txn
|
|
if(CHECK(m_hr=pITransaction->Commit(FALSE, 0, 0), S_OK))
|
|
{
|
|
//Do extended check following Commit
|
|
fResults &= XCHECK(pITransaction, IID_ITransaction, m_hr);
|
|
}
|
|
//Try to get the txn options interface
|
|
if (CHECK(m_hr=pITransaction->GetTransactionInfo(&TxnInfo),XACT_E_NOTRANSACTION))
|
|
{
|
|
//Do extended check following GetOptionsObject
|
|
fResults = XCHECK(pITransaction, IID_ITransaction, m_hr);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
//free objects;
|
|
m_pChgRowset1->FreeJoinTxn();
|
|
if (pITransaction)
|
|
{
|
|
m_pChgRowset1->FreeCoordTxn(pITransaction);
|
|
pITransaction = NULL;
|
|
}
|
|
|
|
ReleaseAllRowsetsAndTxns();
|
|
|
|
if(pITxnOptions){pITxnOptions->Release();}
|
|
|
|
if(fResults)
|
|
return TEST_PASS;
|
|
else
|
|
return TEST_FAIL;
|
|
}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(2)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc Valid Abort call with previous error object existing.
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCExtendedErrors::Variation_2()
|
|
{
|
|
BOOL fResults = FALSE;
|
|
BOID boidReason = BOID_NULL; //Just so we have some value
|
|
ITransaction *pITransaction = NULL;
|
|
|
|
//For each method of the interface, first create an error object on
|
|
//the current thread, then try get S_OK from the ITransactionJoin method.
|
|
//We then check extended errors to verify nothing is set since an
|
|
//error object shouldn't exist following a successful call.
|
|
|
|
//start coordinated txn & join it
|
|
if (CHECK(m_pChgRowset1->StartCoordTxn(&pITransaction,m_fIsoLevel), TRUE))
|
|
{
|
|
//get transactionjoin transaction object.
|
|
if (CHECK(m_pChgRowset1->GetTxnJoin(), S_OK))
|
|
{
|
|
//enlist in coordinated txn
|
|
if (CHECK(m_pChgRowset1->m_pITxnJoin->JoinTransaction ( pITransaction,
|
|
m_fIsoLevel,
|
|
0,
|
|
NULL
|
|
), S_OK))
|
|
{
|
|
//create an error object
|
|
m_pExtError->CauseError();
|
|
|
|
if(CHECK(m_hr=pITransaction->Abort(&boidReason, FALSE, FALSE), S_OK))
|
|
{
|
|
//Do extended check following Abort
|
|
fResults = XCHECK(pITransaction, IID_ITransaction, m_hr);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//free objects;
|
|
m_pChgRowset1->FreeJoinTxn();
|
|
if (pITransaction)
|
|
{
|
|
m_pChgRowset1->FreeCoordTxn(pITransaction);
|
|
pITransaction = NULL;
|
|
}
|
|
|
|
//Cleanup
|
|
ReleaseAllRowsetsAndTxns();
|
|
|
|
if (fResults)
|
|
return TEST_PASS;
|
|
else
|
|
return TEST_FAIL;
|
|
}
|
|
// }}
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(3)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc Valid SetOptions call with previous error object existing.
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCExtendedErrors::Variation_3()
|
|
{
|
|
XACTOPT TxnOptions;
|
|
BOOL fResults = FALSE;
|
|
ITransaction *pITransaction = NULL;
|
|
|
|
//For each method of the interface, first create an error object on
|
|
|
|
//the current thread, then try get S_OK from the ITransactionOptions method.
|
|
//We then check extended errors to verify nothing is set since an
|
|
//error object shouldn't exist following a successful call.
|
|
|
|
//Set time out to non zero
|
|
TxnOptions.ulTimeout = MAX_ULONG;
|
|
TxnOptions.szDescription[0] = '\0';
|
|
|
|
//create an error object
|
|
m_pExtError->CauseError();
|
|
|
|
if (m_pITxnOptions)
|
|
{
|
|
//Set our time out option
|
|
if (CHECK(m_hr=m_pITxnOptions->SetOptions(&TxnOptions), S_OK))
|
|
{
|
|
//Do extended check following SetOptions
|
|
fResults = XCHECK(m_pITxnOptions, IID_ITransactionOptions, m_hr);
|
|
|
|
//start coordinated txn & join it
|
|
if (CHECK(m_pChgRowset1->StartCoordTxn(&pITransaction,m_fIsoLevel), TRUE))
|
|
{
|
|
//get transactionjoin transaction object.
|
|
if (CHECK(m_pChgRowset1->GetTxnJoin(), S_OK))
|
|
{
|
|
//enlist in coordinated txn
|
|
m_hr = m_pChgRowset1->m_pITxnJoin->JoinTransaction ( pITransaction,
|
|
m_fIsoLevel,
|
|
0,
|
|
m_pITxnOptions
|
|
);
|
|
//free objects;
|
|
m_pChgRowset1->FreeJoinTxn();
|
|
ReleaseAllRowsetsAndTxns();
|
|
|
|
//Either of these is acceptable
|
|
if (m_hr == S_OK || m_hr == XACT_E_NOTIMEOUT)
|
|
{
|
|
fResults = TRUE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return TEST_SKIPPED;
|
|
}
|
|
if (pITransaction)
|
|
{
|
|
m_pChgRowset1->FreeCoordTxn(pITransaction);
|
|
pITransaction = NULL;
|
|
}
|
|
if(fResults)
|
|
{
|
|
return TEST_PASS;
|
|
}
|
|
else
|
|
{
|
|
return TEST_FAIL;
|
|
}
|
|
}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(4)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc Valid GetOptions call with previous error object existing.
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCExtendedErrors::Variation_4()
|
|
{
|
|
ITransactionOptions *pITxnOptions = NULL;
|
|
BOOL fResults = FALSE;
|
|
XACTOPT TxnOptions;
|
|
|
|
//For each method of the interface, first create an error object on
|
|
//the current thread, then try get S_OK from the ITransactionOptions method.
|
|
//We then check extended errors to verify nothing is set since an
|
|
//error object shouldn't exist following a successful call.
|
|
|
|
//get transactionjoin transaction object.
|
|
if (CHECK(m_pChgRowset1->GetTxnJoin(), S_OK))
|
|
{
|
|
//enlist in coordinated txn
|
|
if (CHECK(m_pChgRowset1->m_pITxnJoin->GetOptionsObject(&pITxnOptions), S_OK))
|
|
{
|
|
//create an error object
|
|
m_pExtError->CauseError();
|
|
|
|
//Make sure we can also get the options with
|
|
//TxnOptions allocated on stack (so we know
|
|
//provider isn't trying to free the memory)
|
|
if (CHECK(m_hr=pITxnOptions->GetOptions(&TxnOptions), S_OK))
|
|
{
|
|
//Do extended check following GetOptions
|
|
fResults = XCHECK(pITxnOptions, IID_ITransactionOptions, m_hr);
|
|
}
|
|
|
|
if(pITxnOptions){pITxnOptions->Release();}
|
|
}
|
|
}
|
|
m_pChgRowset1->FreeJoinTxn();
|
|
|
|
if (fResults)
|
|
return TEST_PASS;
|
|
else
|
|
return TEST_FAIL;
|
|
}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(5)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc XACT_E_NOTSUPPORTED Commit call with previous error object existing
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCExtendedErrors::Variation_5()
|
|
{
|
|
BOOL fResults = FALSE;
|
|
ITransaction *pITransaction = NULL;
|
|
|
|
//For each method of the interface, first create an error object on
|
|
//the current thread, then try get a failure from the ITransactionJoin method.
|
|
//We then check extended errors to verify the right extended error behavior.
|
|
|
|
//start coordinated txn & join it
|
|
if (CHECK(m_pChgRowset1->StartCoordTxn(&pITransaction,m_fIsoLevel), TRUE))
|
|
{
|
|
//get transactionjoin transaction object.
|
|
if (CHECK(m_pChgRowset1->GetTxnJoin(), S_OK))
|
|
{
|
|
//enlist in coordinated txn
|
|
if (CHECK(m_pChgRowset1->m_pITxnJoin->JoinTransaction ( pITransaction,
|
|
m_fIsoLevel,
|
|
0,
|
|
NULL
|
|
), S_OK))
|
|
{
|
|
//create an error object
|
|
m_pExtError->CauseError();
|
|
|
|
//Check for proper return code for given parameters
|
|
if( CHECK(m_hr=pITransaction->Commit(FALSE, (XACTTC_SYNC_PHASETWO + 1), 0), XACT_E_NOTSUPPORTED))
|
|
{
|
|
//Do extended check following Commit
|
|
fResults = XCHECK(pITransaction, IID_ITransaction, m_hr);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
//Cleanup
|
|
//free objects;
|
|
m_pChgRowset1->FreeJoinTxn();
|
|
if (pITransaction)
|
|
{
|
|
m_pChgRowset1->FreeCoordTxn(pITransaction);
|
|
pITransaction = NULL;
|
|
}
|
|
|
|
ReleaseAllRowsetsAndTxns();
|
|
|
|
if (fResults)
|
|
return TEST_PASS;
|
|
else
|
|
return TEST_FAIL;
|
|
}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(6)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc XACT_E_NOISORETAIN JoinTransaction call with previous error object existing
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCExtendedErrors::Variation_6()
|
|
{
|
|
BOOL fResults = FALSE;
|
|
ITransaction *pITransaction = NULL;
|
|
|
|
//For each method of the interface, first create an error object on
|
|
//the current thread, then try get a failure from the ITransactionJoin method.
|
|
//We then check extended errors to verify the right extended error behavior.
|
|
|
|
//create an error object
|
|
m_pExtError->CauseError();
|
|
|
|
//start coordinated txn & join it
|
|
if (CHECK(m_pChgRowset1->StartCoordTxn(&pITransaction,m_fIsoLevel), TRUE))
|
|
{
|
|
//get transactionjoin transaction object.
|
|
if (CHECK(m_pChgRowset1->GetTxnJoin(), S_OK))
|
|
{
|
|
//enlist in coordinated txn
|
|
if (CHECK(m_pChgRowset1->m_pITxnJoin->JoinTransaction ( pITransaction,
|
|
m_fIsoLevel,
|
|
1,
|
|
NULL
|
|
), XACT_E_NOISORETAIN))
|
|
{
|
|
//Do extended check following JoinTransaction
|
|
fResults = XCHECK(m_pChgRowset1->m_pITxnJoin, IID_ITransactionJoin, XACT_E_NOISORETAIN);
|
|
}
|
|
//enlist in coordinated txn
|
|
if (CHECK(m_pChgRowset1->m_pITxnJoin->JoinTransaction ( pITransaction,
|
|
m_fIsoLevel,
|
|
-1,
|
|
NULL
|
|
), XACT_E_NOISORETAIN))
|
|
{
|
|
//Do extended check following JoinTransaction
|
|
fResults = XCHECK(m_pChgRowset1->m_pITxnJoin, IID_ITransactionJoin, XACT_E_NOISORETAIN);
|
|
}
|
|
//enlist in coordinated txn
|
|
if (CHECK(m_pChgRowset1->m_pITxnJoin->JoinTransaction ( pITransaction,
|
|
m_fIsoLevel,
|
|
0,
|
|
NULL
|
|
), S_OK))
|
|
{
|
|
//Do extended check following JoinTransaction
|
|
fResults = XCHECK(m_pChgRowset1->m_pITxnJoin, IID_ITransactionJoin, S_OK);
|
|
fResults=TRUE;
|
|
}
|
|
}
|
|
}
|
|
//free objects;
|
|
m_pChgRowset1->FreeJoinTxn();
|
|
if (pITransaction)
|
|
{
|
|
m_pChgRowset1->FreeCoordTxn(pITransaction);
|
|
pITransaction = NULL;
|
|
}
|
|
|
|
if(fResults)
|
|
return TEST_PASS;
|
|
else
|
|
return TEST_FAIL;
|
|
}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(7)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc E_INVALIDARG GetTransactionInfo call with previous error object existing
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCExtendedErrors::Variation_7()
|
|
{
|
|
BOOL fResults = FALSE;
|
|
ITransaction *pITransaction = NULL;
|
|
|
|
//For each method of the interface, first create an error object on
|
|
//the current thread, then try get a failure from the ITransactionJoin method.
|
|
//We then check extended errors to verify the right extended error behavior.
|
|
|
|
//start coordinated txn & join it
|
|
if (CHECK(m_pChgRowset1->StartCoordTxn(&pITransaction,m_fIsoLevel), TRUE))
|
|
{
|
|
//get transactionjoin transaction object.
|
|
if (CHECK(m_pChgRowset1->GetTxnJoin(), S_OK))
|
|
{
|
|
//enlist in coordinated txn
|
|
if (CHECK(m_pChgRowset1->m_pITxnJoin->JoinTransaction ( pITransaction,
|
|
m_fIsoLevel,
|
|
0,
|
|
NULL
|
|
), S_OK))
|
|
{
|
|
//create an error object
|
|
m_pExtError->CauseError();
|
|
|
|
//Check for invalid arg on pinfo = NULL
|
|
if (CHECK(m_hr=pITransaction->GetTransactionInfo(NULL), E_INVALIDARG))
|
|
{
|
|
//Do extended check following GetTransactionInfo
|
|
fResults = XCHECK(pITransaction, IID_ITransaction, m_hr);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
//Cleanup
|
|
ReleaseAllRowsetsAndTxns();
|
|
//free objects;
|
|
m_pChgRowset1->FreeJoinTxn();
|
|
if (pITransaction)
|
|
{
|
|
m_pChgRowset1->FreeCoordTxn(pITransaction);
|
|
pITransaction = NULL;
|
|
}
|
|
|
|
if (fResults)
|
|
return TEST_PASS;
|
|
else
|
|
return TEST_FAIL;
|
|
}
|
|
// }}
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(8)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc E_INVALIDARG GetOptions call with previous error object existing
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCExtendedErrors::Variation_8()
|
|
{
|
|
BOOL fResults = FALSE;
|
|
ITransactionOptions *pITxnOptions = NULL;
|
|
|
|
//For each method of the interface, first create an error object on
|
|
//the current thread, then try get a failure from the ITransitionOptions method.
|
|
//We then check extended errors to verify the right extended error behavior.
|
|
|
|
//get transactionjoin transaction object.
|
|
if (CHECK(m_pChgRowset1->GetTxnJoin(), S_OK))
|
|
{
|
|
if (CHECK(m_pChgRowset1->m_pITxnJoin->GetOptionsObject(&pITxnOptions), S_OK))
|
|
{
|
|
//create an error object
|
|
m_pExtError->CauseError();
|
|
|
|
//Expect invalid arg for NULL
|
|
if (CHECK(m_hr=pITxnOptions->SetOptions(NULL), E_INVALIDARG))
|
|
{
|
|
//Do extended check following SetOptions
|
|
fResults = XCHECK(pITxnOptions, IID_ITransactionOptions, m_hr);
|
|
}
|
|
}
|
|
if(pITxnOptions){pITxnOptions->Release();}
|
|
}
|
|
//free objects;
|
|
m_pChgRowset1->FreeJoinTxn();
|
|
|
|
if (fResults)
|
|
return TEST_PASS;
|
|
else
|
|
return TEST_FAIL;
|
|
}
|
|
// }}
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(9)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc E_INVALIDARG SetOptions call with previous error object existing
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCExtendedErrors::Variation_9()
|
|
{
|
|
ITransactionOptions *pITxnOptions = NULL;
|
|
BOOL fResults = FALSE;
|
|
|
|
//For each method of the interface, first create an error object on
|
|
//the current thread, then try get a failure from the ITransactionOptions method.
|
|
//We then check extended errors to verify the right extended error behavior.
|
|
|
|
//get transactionjoin transaction object.
|
|
if (CHECK(m_pChgRowset1->GetTxnJoin(), S_OK))
|
|
{
|
|
if (CHECK(m_pChgRowset1->m_pITxnJoin->GetOptionsObject(&pITxnOptions), S_OK))
|
|
{
|
|
//create an error object
|
|
m_pExtError->CauseError();
|
|
|
|
//Make sure we can also get the options
|
|
if (CHECK(m_hr=pITxnOptions->GetOptions(NULL), E_INVALIDARG))
|
|
{
|
|
//Do extended check following GetOptions
|
|
fResults = XCHECK(pITxnOptions, IID_ITransactionOptions, m_hr);
|
|
}
|
|
if(pITxnOptions){pITxnOptions->Release();}
|
|
}
|
|
}
|
|
//free objects;
|
|
m_pChgRowset1->FreeJoinTxn();
|
|
|
|
if (fResults)
|
|
return TEST_PASS;
|
|
else
|
|
return TEST_FAIL;
|
|
}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(10)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc XACT_E_ISOLATIONLEVEL NULL & INVALID ISOLEVEL
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCExtendedErrors::Variation_10()
|
|
{
|
|
BOOL fResults = FALSE;
|
|
ITransaction *pITransaction = NULL;
|
|
|
|
//For each method of the interface, with no error object on
|
|
//the current thread, try get a failure from the ITransactionJoin method.
|
|
//We then check extended errors to verify the right extended error behavior.
|
|
|
|
//start coordinated txn & join it
|
|
if (CHECK(m_pChgRowset1->StartCoordTxn(&pITransaction,m_fIsoLevel), TRUE))
|
|
{
|
|
//get transactionjoin transaction object.
|
|
if (CHECK(m_pChgRowset1->GetTxnJoin(), S_OK))
|
|
{
|
|
//enlist in coordinated txn
|
|
if (CHECK(m_pChgRowset1->m_pITxnJoin->JoinTransaction ( pITransaction,
|
|
ISOLATIONLEVEL_CHAOS |
|
|
ISOLATIONLEVEL_READUNCOMMITTED |
|
|
ISOLATIONLEVEL_READCOMMITTED |
|
|
ISOLATIONLEVEL_SERIALIZABLE,
|
|
0,
|
|
NULL
|
|
), XACT_E_ISOLATIONLEVEL))
|
|
{
|
|
//Do extended check following JoinTransaction
|
|
fResults = XCHECK(m_pChgRowset1->m_pITxnJoin, IID_ITransactionJoin, XACT_E_ISOLATIONLEVEL);
|
|
}
|
|
}
|
|
}
|
|
//free objects;
|
|
m_pChgRowset1->FreeJoinTxn();
|
|
if (pITransaction)
|
|
{
|
|
m_pChgRowset1->FreeCoordTxn(pITransaction);
|
|
pITransaction = NULL;
|
|
}
|
|
|
|
if(fResults)
|
|
return TEST_PASS;
|
|
else
|
|
return TEST_FAIL;
|
|
}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(11)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc E_INVALIDARG GetOptionObject calls no with previous error object existing
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCExtendedErrors::Variation_11()
|
|
{
|
|
BOOL fResults = FALSE;
|
|
ITransactionJoin *pITransactionJoin = NULL;
|
|
|
|
//get transactionjoin transaction object.
|
|
if (CHECK(m_pChgRowset1->GetTxnJoin(), S_OK))
|
|
{
|
|
if (CHECK(m_pChgRowset1->m_pITxnJoin->GetOptionsObject(NULL), E_INVALIDARG))
|
|
{
|
|
//Do extended check following GetOptionsObject
|
|
fResults = XCHECK(pITransactionJoin, IID_ITransactionJoin, m_hr);
|
|
}
|
|
}
|
|
|
|
//free objects;
|
|
m_pChgRowset1->FreeJoinTxn();
|
|
|
|
if(fResults)
|
|
return TEST_PASS;
|
|
else
|
|
return TEST_FAIL;
|
|
}
|
|
// }}
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(12)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc E_INVALIDARG SetOptions calls with no previous error object existing
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCExtendedErrors::Variation_12()
|
|
{
|
|
BOOL fResults = FALSE;
|
|
ITransactionOptions *pITxnOptions = NULL;
|
|
|
|
//get transactionjoin transaction object.
|
|
if (CHECK(m_pChgRowset1->GetTxnJoin(), S_OK))
|
|
{
|
|
if (CHECK(m_pChgRowset1->m_pITxnJoin->GetOptionsObject(&pITxnOptions), S_OK))
|
|
{
|
|
//Expect invalid arg for NULL
|
|
if (CHECK(m_hr=pITxnOptions->SetOptions(NULL), E_INVALIDARG))
|
|
{
|
|
//Do extended check following SetOptions
|
|
fResults = XCHECK(pITxnOptions, IID_ITransactionOptions, m_hr);
|
|
}
|
|
}
|
|
if(pITxnOptions){pITxnOptions->Release();}
|
|
}
|
|
//free objects;
|
|
m_pChgRowset1->FreeJoinTxn();
|
|
|
|
if (fResults)
|
|
return TEST_PASS;
|
|
else
|
|
return TEST_FAIL;
|
|
}
|
|
// }}
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(13)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc E_INVALIDARG GetOptions calls with no previous error object existing
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCExtendedErrors::Variation_13()
|
|
{
|
|
ITransactionOptions *pITxnOptions = NULL;
|
|
BOOL fResults = FALSE;
|
|
|
|
//get transactionjoin transaction object.
|
|
if (CHECK(m_pChgRowset1->GetTxnJoin(), S_OK))
|
|
{
|
|
if (CHECK(m_pChgRowset1->m_pITxnJoin->GetOptionsObject(&pITxnOptions), S_OK))
|
|
{
|
|
//Make sure we can also get the options
|
|
if (CHECK(m_hr=pITxnOptions->GetOptions(NULL), E_INVALIDARG))
|
|
{
|
|
//Do extended check following GetOptions
|
|
fResults = XCHECK(pITxnOptions, IID_ITransactionOptions, m_hr);
|
|
}
|
|
}
|
|
if(pITxnOptions){pITxnOptions->Release();}
|
|
}
|
|
//free objects;
|
|
m_pChgRowset1->FreeJoinTxn();
|
|
|
|
if (fResults)
|
|
return TEST_PASS;
|
|
else
|
|
return TEST_FAIL;
|
|
}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(14)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc Valid Abort calls with previous error object existing, check error on ITransaction
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCExtendedErrors::Variation_14()
|
|
{
|
|
BOOL fResults = FALSE;
|
|
BOID boidReason = BOID_NULL; //Just so we have some value
|
|
ITransaction *pITransaction = NULL;
|
|
|
|
//start coordinated txn & join it
|
|
if (CHECK(m_pChgRowset1->StartCoordTxn(&pITransaction,m_fIsoLevel), TRUE))
|
|
{
|
|
//For each method of the interface, first create an error object on
|
|
//the current thread, then try get S_OK from the ITransactionJoin method.
|
|
//We then check extended errors on ITransaction interface to verify nothing
|
|
//is set since an error object shouldn't exist following a successful call.
|
|
|
|
//Check for proper return code for given parameters
|
|
//create an error object
|
|
m_pExtError->CauseError();
|
|
|
|
if(CHECK(m_hr=pITransaction->Abort(&boidReason, FALSE, FALSE), S_OK))
|
|
{
|
|
//Do extended check on ITransaction following Abort
|
|
fResults = XCHECK(pITransaction, IID_ITransaction, m_hr);
|
|
}
|
|
}
|
|
|
|
//free objects;
|
|
if (pITransaction)
|
|
{
|
|
m_pChgRowset1->FreeCoordTxn(pITransaction);
|
|
pITransaction = NULL;
|
|
}
|
|
|
|
//Cleanup
|
|
ReleaseAllRowsetsAndTxns();
|
|
|
|
if (fResults)
|
|
return TEST_PASS;
|
|
else
|
|
return TEST_FAIL;
|
|
}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(15)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc Valid TransactionLocal calls with previous error object existing, check error on ITransaction
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCExtendedErrors::Variation_15()
|
|
{
|
|
ULONG ulTxnLvl1 = 0;
|
|
BOOL fResults = FALSE;
|
|
XACTTRANSINFO TxnInfo;
|
|
ITransaction *pITransaction = NULL;
|
|
|
|
//start coordinated txn & join it
|
|
if (CHECK(m_pChgRowset1->StartCoordTxn(&pITransaction,m_fIsoLevel), TRUE))
|
|
{
|
|
//get transactionjoin transaction object.
|
|
if (CHECK(m_pChgRowset1->GetTxnJoin(), S_OK))
|
|
{
|
|
//enlist in coordinated txn
|
|
if (CHECK(m_pChgRowset1->m_pITxnJoin->JoinTransaction ( pITransaction,
|
|
m_fIsoLevel,
|
|
0,
|
|
NULL
|
|
), S_OK))
|
|
{
|
|
//For each method of the interface, first create an error object on
|
|
//the current thread, then try get S_OK from the ITransactionJoin method.
|
|
//We then check extended errors on ITransaction interface to verify nothing
|
|
//is set since an error object shouldn't exist following a successful call.
|
|
|
|
//create an error object
|
|
m_pExtError->CauseError();
|
|
|
|
//call GeTransactionInfo
|
|
if (CHECK(m_hr=pITransaction->GetTransactionInfo(&TxnInfo), S_OK))
|
|
{
|
|
//Do extended check following JoinTransaction
|
|
fResults = XCHECK(pITransaction, IID_ITransaction, m_hr);
|
|
}
|
|
|
|
//This will succeed if nested txns are supported, else return
|
|
//XACT_E_XTIONEXISTS
|
|
m_hr = m_pChgRowset1->m_pITxnLocal->StartTransaction(m_fIsoLevel,0, NULL, &ulTxnLvl1);
|
|
|
|
if (m_hr == S_OK)
|
|
{
|
|
//Make sure the nesting worked
|
|
COMPARE(ulTxnLvl1, 2);
|
|
}
|
|
else
|
|
{
|
|
//Make sure we got the right return value
|
|
CHECK(m_hr, XACT_E_XTIONEXISTS);
|
|
}
|
|
|
|
//create an error object
|
|
m_pExtError->CauseError();
|
|
|
|
//End the txn -- this should end both levels, if applicable
|
|
if(CHECK(m_hr=pITransaction->Commit(FALSE, 0, 0), S_OK))
|
|
{
|
|
//Do extended check following Commit
|
|
fResults &= XCHECK(pITransaction, IID_ITransaction, m_hr);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
//free objects;
|
|
m_pChgRowset1->FreeJoinTxn();
|
|
if (pITransaction)
|
|
{
|
|
m_pChgRowset1->FreeCoordTxn(pITransaction);
|
|
pITransaction = NULL;
|
|
}
|
|
|
|
ReleaseAllRowsetsAndTxns();
|
|
|
|
if(fResults)
|
|
return TEST_PASS;
|
|
else
|
|
return TEST_FAIL;
|
|
}
|
|
// }}
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(16)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc punkTransactionCoord NULL isoflag ignored
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCExtendedErrors::Variation_16()
|
|
{
|
|
BOOL fResults = FALSE;
|
|
ITransaction *pITransaction = NULL;
|
|
HRESULT hr = S_OK;
|
|
|
|
//For each method of the interface, first create an error object on
|
|
//the current thread, then try get a failure from the ITransactionJoin method.
|
|
//We then check extended errors to verify the right extended error behavior.
|
|
|
|
//create an error object
|
|
m_pExtError->CauseError();
|
|
|
|
//start coordinated txn & join it
|
|
if (CHECK(m_pChgRowset1->StartCoordTxn(&pITransaction,m_fIsoLevel), TRUE))
|
|
{
|
|
//get transactionjoin transaction object.
|
|
if (CHECK(m_pChgRowset1->GetTxnJoin(), S_OK))
|
|
{
|
|
//join MTS
|
|
if (CHECK(m_pChgRowset1->m_pITxnJoin->JoinTransaction ( pITransaction,
|
|
m_fIsoLevel,
|
|
0,
|
|
NULL
|
|
), S_OK))
|
|
{
|
|
//end the mts coordinated txn, abort it, zombies session
|
|
if (CHECK(pITransaction->Abort(NULL, FALSE, FALSE), S_OK))
|
|
{
|
|
//unelinst from MTS, punkTransactionCoord NULL isoflag ignored
|
|
hr=m_pChgRowset1->m_pITxnJoin->JoinTransaction ( NULL,
|
|
m_fIsoLevel,
|
|
5,
|
|
NULL
|
|
);
|
|
if(XACT_E_XTIONEXISTS==hr || S_OK==hr)
|
|
{
|
|
fResults=TRUE;
|
|
goto CLEANUP;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
CLEANUP:
|
|
//free objects;
|
|
m_pChgRowset1->FreeJoinTxn();
|
|
if (pITransaction)
|
|
{
|
|
m_pChgRowset1->FreeCoordTxn(pITransaction);
|
|
pITransaction = NULL;
|
|
}
|
|
|
|
if(fResults)
|
|
return TEST_PASS;
|
|
else
|
|
return TEST_FAIL;
|
|
}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(17)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc punkTransactionCoord NULL isoflag ignored
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCExtendedErrors::Variation_17()
|
|
{
|
|
BOOL fResults = FALSE;
|
|
ITransaction *pITransaction = NULL;
|
|
HRESULT hr = S_OK;
|
|
|
|
//For each method of the interface, first create an error object on
|
|
//the current thread, then try get a failure from the ITransactionJoin method.
|
|
//We then check extended errors to verify the right extended error behavior.
|
|
|
|
//create an error object
|
|
m_pExtError->CauseError();
|
|
|
|
//start coordinated txn & join it
|
|
if (CHECK(m_pChgRowset1->StartCoordTxn(&pITransaction,m_fIsoLevel), TRUE))
|
|
{
|
|
//get transactionjoin transaction object.
|
|
if (CHECK(m_pChgRowset1->GetTxnJoin(), S_OK))
|
|
{
|
|
//join MTS
|
|
if (CHECK(m_pChgRowset1->m_pITxnJoin->JoinTransaction ( pITransaction,
|
|
m_fIsoLevel,
|
|
0,
|
|
NULL
|
|
), S_OK))
|
|
{
|
|
//end the mts coordinated txn, abort it, zombies session
|
|
if (CHECK(pITransaction->Abort(NULL, FALSE, FALSE), S_OK))
|
|
{
|
|
//unelinst from MTS, punkTransactionCoord NULL isoflag ignored
|
|
hr=m_pChgRowset1->m_pITxnJoin->JoinTransaction ( NULL,
|
|
m_fIsoLevel,
|
|
-1,
|
|
NULL
|
|
);
|
|
if(XACT_E_XTIONEXISTS == hr || S_OK == hr)
|
|
{
|
|
fResults=TRUE;
|
|
goto CLEANUP;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
CLEANUP:
|
|
//free objects;
|
|
m_pChgRowset1->FreeJoinTxn();
|
|
if (pITransaction)
|
|
{
|
|
m_pChgRowset1->FreeCoordTxn(pITransaction);
|
|
pITransaction = NULL;
|
|
}
|
|
|
|
if(fResults)
|
|
return TEST_PASS;
|
|
else
|
|
return TEST_FAIL;
|
|
}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(18)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc punkTransactionCoord NULL isolevel ignored
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCExtendedErrors::Variation_18()
|
|
{
|
|
BOOL fResults = FALSE;
|
|
ITransaction *pITransaction = NULL;
|
|
HRESULT hr = S_OK;
|
|
|
|
//For each method of the interface, with no error object on
|
|
//the current thread, try get a failure from the ITransactionJoin method.
|
|
//We then check extended errors to verify the right extended error behavior.
|
|
|
|
//start coordinated txn & join it
|
|
if (CHECK(m_pChgRowset1->StartCoordTxn(&pITransaction,m_fIsoLevel), TRUE))
|
|
{
|
|
//get transactionjoin transaction object.
|
|
if (CHECK(m_pChgRowset1->GetTxnJoin(), S_OK))
|
|
{
|
|
//join MTS
|
|
if (CHECK(m_pChgRowset1->m_pITxnJoin->JoinTransaction ( pITransaction,
|
|
m_fIsoLevel,
|
|
0,
|
|
NULL
|
|
), S_OK))
|
|
{
|
|
//end the mts coordinated txn, abort it, zombies session
|
|
if (CHECK(pITransaction->Abort(NULL, FALSE, FALSE), S_OK))
|
|
{
|
|
//punkTransactionCoord NULL isolevel ignored
|
|
hr=m_pChgRowset1->m_pITxnJoin->JoinTransaction ( NULL,
|
|
ISOLATIONLEVEL_CHAOS |
|
|
ISOLATIONLEVEL_READUNCOMMITTED |
|
|
ISOLATIONLEVEL_READCOMMITTED |
|
|
ISOLATIONLEVEL_SERIALIZABLE,
|
|
0,
|
|
NULL
|
|
);
|
|
if(XACT_E_XTIONEXISTS==hr || S_OK==hr)
|
|
{
|
|
fResults=TRUE;
|
|
goto CLEANUP;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
CLEANUP:
|
|
//free objects;
|
|
m_pChgRowset1->FreeJoinTxn();
|
|
if (pITransaction)
|
|
{
|
|
m_pChgRowset1->FreeCoordTxn(pITransaction);
|
|
pITransaction = NULL;
|
|
}
|
|
|
|
if(fResults)
|
|
return TEST_PASS;
|
|
else
|
|
return TEST_FAIL;
|
|
}
|
|
// }}
|
|
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(19)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc punkTransactionCoord NULL isolevel ignored
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCExtendedErrors::Variation_19()
|
|
{
|
|
BOOL fResults = FALSE;
|
|
ITransaction *pITransaction = NULL;
|
|
HRESULT hr = S_OK;
|
|
|
|
//For each method of the interface, with no error object on
|
|
//the current thread, try get a failure from the ITransactionJoin method.
|
|
//We then check extended errors to verify the right extended error behavior.
|
|
|
|
//start coordinated txn & join it
|
|
if (CHECK(m_pChgRowset1->StartCoordTxn(&pITransaction,m_fIsoLevel), TRUE))
|
|
{
|
|
//get transactionjoin transaction object.
|
|
if (CHECK(m_pChgRowset1->GetTxnJoin(), S_OK))
|
|
{
|
|
//join MTS
|
|
if (CHECK(m_pChgRowset1->m_pITxnJoin->JoinTransaction ( pITransaction,
|
|
m_fIsoLevel,
|
|
0,
|
|
NULL
|
|
), S_OK))
|
|
{
|
|
//end the mts coordinated txn, abort it, zombies session
|
|
if (CHECK(pITransaction->Abort(NULL, FALSE, FALSE), S_OK))
|
|
{
|
|
//punkTransactionCoord NULL isolevel ignored
|
|
hr=m_pChgRowset1->m_pITxnJoin->JoinTransaction ( NULL,
|
|
0,
|
|
0,
|
|
NULL
|
|
);
|
|
if(XACT_E_XTIONEXISTS==hr || hr==S_OK)
|
|
{
|
|
fResults=TRUE;
|
|
goto CLEANUP;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
CLEANUP:
|
|
//free objects;
|
|
m_pChgRowset1->FreeJoinTxn();
|
|
if (pITransaction)
|
|
{
|
|
m_pChgRowset1->FreeCoordTxn(pITransaction);
|
|
pITransaction = NULL;
|
|
}
|
|
|
|
if(fResults)
|
|
return TEST_PASS;
|
|
else
|
|
return TEST_FAIL;
|
|
}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(20)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc XACT_E_ISOLATIONLEVEL INVALID ISOLEVEL
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCExtendedErrors::Variation_20()
|
|
{
|
|
BOOL fResults = FALSE;
|
|
ITransaction *pITransaction = NULL;
|
|
|
|
//For each method of the interface, with no error object on
|
|
//the current thread, try get a failure from the ITransactionJoin method.
|
|
//We then check extended errors to verify the right extended error behavior.
|
|
|
|
//start coordinated txn & join it
|
|
if (CHECK(m_pChgRowset1->StartCoordTxn(&pITransaction,m_fIsoLevel), TRUE))
|
|
{
|
|
//get transactionjoin transaction object.
|
|
if (CHECK(m_pChgRowset1->GetTxnJoin(), S_OK))
|
|
{
|
|
//join MTS, invalid isolevel
|
|
if (CHECK(m_pChgRowset1->m_pITxnJoin->JoinTransaction ( pITransaction,
|
|
0,
|
|
0,
|
|
NULL
|
|
), XACT_E_ISOLATIONLEVEL))
|
|
{
|
|
//Do extended check following JoinTransaction
|
|
fResults=TRUE;
|
|
fResults = XCHECK(m_pChgRowset1->m_pITxnJoin, IID_ITransactionJoin, XACT_E_ISOLATIONLEVEL);
|
|
}
|
|
}
|
|
}
|
|
//free objects;
|
|
m_pChgRowset1->FreeJoinTxn();
|
|
if (pITransaction)
|
|
{
|
|
m_pChgRowset1->FreeCoordTxn(pITransaction);
|
|
pITransaction = NULL;
|
|
}
|
|
|
|
if(fResults)
|
|
return TEST_PASS;
|
|
else
|
|
return TEST_FAIL;
|
|
}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(21)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc Start/Join/XACT_E_XTIONEXISTS
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCExtendedErrors::Variation_21()
|
|
{
|
|
ULONG ulTxnLvl1 = 0;
|
|
BOOL fResults = FALSE;
|
|
ITransaction *pITransaction = NULL;
|
|
HRESULT hr;
|
|
|
|
|
|
if(gfBlocked)
|
|
{
|
|
return TEST_SKIPPED;
|
|
}
|
|
//start coordinated txn & join it
|
|
if (CHECK(m_pChgRowset1->StartCoordTxn(&pITransaction,m_fIsoLevel), TRUE))
|
|
{
|
|
//get transactionjoin transaction object.
|
|
if (CHECK(m_pChgRowset1->GetTxnJoin(), S_OK))
|
|
{
|
|
//enlist in coordinated txn
|
|
if (CHECK(m_pChgRowset1->m_pITxnJoin->JoinTransaction ( pITransaction,
|
|
m_fIsoLevel,
|
|
0,
|
|
NULL
|
|
), S_OK))
|
|
{
|
|
//This will succeed if nested txns are supported, else return
|
|
//XACT_E_XTIONEXISTS
|
|
hr=m_pChgRowset1->m_pITxnLocal->StartTransaction(m_fIsoLevel,0, NULL, &ulTxnLvl1);
|
|
|
|
if (S_OK==hr||XACT_E_XTIONEXISTS==hr)
|
|
{
|
|
//enlist in coordinated txn
|
|
if (CHECK(m_pChgRowset1->m_pITxnJoin->JoinTransaction ( pITransaction,
|
|
m_fIsoLevel,
|
|
0,
|
|
NULL
|
|
), XACT_E_XTIONEXISTS))
|
|
{
|
|
fResults = TRUE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
//free objects;
|
|
m_pChgRowset1->FreeJoinTxn();
|
|
if (pITransaction)
|
|
{
|
|
m_pChgRowset1->FreeCoordTxn(pITransaction);
|
|
pITransaction = NULL;
|
|
}
|
|
|
|
ReleaseAllRowsetsAndTxns();
|
|
|
|
if(fResults)
|
|
return TEST_PASS;
|
|
else
|
|
return TEST_FAIL;
|
|
}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_TERMINATE_METHOD
|
|
//--------------------------------------------------------------------
|
|
// @mfunc TestCase Termination Routine
|
|
//
|
|
// @rdesc TRUE or FALSE
|
|
//
|
|
BOOL TCExtendedErrors::Terminate()
|
|
{
|
|
if (!m_fOnAccess)
|
|
{
|
|
// Release the Objects
|
|
if( m_pITxnOptions )
|
|
if(m_pITxnOptions){m_pITxnOptions->Release();}
|
|
}
|
|
//if (m_pExtError)
|
|
// delete m_pExtError;
|
|
//m_pExtError = NULL;
|
|
|
|
// {{ TCW_TERM_BASECLASS_CHECK2
|
|
return(CTxnImmed::Terminate());
|
|
|
|
} // }}
|
|
// }}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_TC_PROTOTYPE(TCNestedTransactions)
|
|
//*-----------------------------------------------------------------------
|
|
//| Test Case: TCNestedTransactions
|
|
//| Created: 02/14/98
|
|
//*-----------------------------------------------------------------------
|
|
|
|
//--------------------------------------------------------------------
|
|
// @mfunc TestCase Initialization Routine
|
|
//
|
|
// @rdesc TRUE or FALSE
|
|
//
|
|
BOOL TCNestedTransactions::Init()
|
|
{
|
|
// {{ TCW_INIT_BASECLASS_CHECK
|
|
if(CTxnImmed::Init())
|
|
// }}
|
|
{
|
|
//the jet engine (access) does not support distributed transactions
|
|
if (m_fOnAccess)
|
|
{
|
|
return TEST_SKIPPED;
|
|
}
|
|
else
|
|
{
|
|
return TEST_PASS;
|
|
}
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(1)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc Legal - Nested Transaction Supported?
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCNestedTransactions::Variation_1()
|
|
{
|
|
BOOL fResults = FALSE;
|
|
ITransaction *pITransaction = NULL;
|
|
|
|
//start coordinated txn & join it
|
|
if (CHECK(m_pChgRowset1->StartCoordTxn(&pITransaction,m_fIsoLevel), TRUE))
|
|
{
|
|
//get transactionjoin transaction object.
|
|
if (CHECK(m_pChgRowset1->GetTxnJoin(), S_OK))
|
|
{
|
|
if (CHECK(m_pChgRowset1->m_pITxnJoin->JoinTransaction ( pITransaction,
|
|
m_fIsoLevel,
|
|
0,
|
|
NULL
|
|
), S_OK))
|
|
{
|
|
//this local transaction should start a nested transaction
|
|
m_hr = m_pChgRowset1->StartTxn(m_fIsoLevel);
|
|
//S_OK if nesting is supported
|
|
//XACT_EXTIONEXISTS if nesting is not supported
|
|
if (S_OK==m_hr || XACT_E_XTIONEXISTS==m_hr)
|
|
{
|
|
fResults = TRUE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//clean up these txns
|
|
//end the mts coordinated txn, abort it, zombies session
|
|
pITransaction->Abort(NULL, FALSE, FALSE);
|
|
|
|
//unenlist the session from the dead dist txn
|
|
m_pChgRowset1->m_pITxnJoin->JoinTransaction ( NULL,
|
|
ISOLATIONLEVEL_UNSPECIFIED,
|
|
0,
|
|
NULL
|
|
);
|
|
//free objects;
|
|
m_pChgRowset1->FreeJoinTxn();
|
|
if (pITransaction)
|
|
{
|
|
m_pChgRowset1->FreeCoordTxn(pITransaction);
|
|
pITransaction = NULL;
|
|
}
|
|
|
|
ReleaseAllRowsetsAndTxns();
|
|
|
|
return fResults;
|
|
}
|
|
// }}
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(2)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc Illegal Nested Transaction - 2 ITransactionJoins
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCNestedTransactions::Variation_2()
|
|
{
|
|
BOOL fResults = FALSE;
|
|
ITransaction *pITransaction = NULL;
|
|
HRESULT hr = S_OK;
|
|
|
|
if(gfBlocked)
|
|
{
|
|
return TEST_SKIPPED;
|
|
}
|
|
//start coordinated txn & join it
|
|
if (CHECK(m_pChgRowset1->StartCoordTxn(&pITransaction,m_fIsoLevel), TRUE))
|
|
{
|
|
//get transactionjoin transaction object.
|
|
if (CHECK(m_pChgRowset1->GetTxnJoin(), S_OK))
|
|
{
|
|
//coordinated txns are not allowed if local txns are current
|
|
if (CHECK(m_pChgRowset1->m_pITxnJoin->JoinTransaction ( pITransaction,
|
|
m_fIsoLevel,
|
|
0,
|
|
NULL
|
|
), S_OK))
|
|
{
|
|
// Online Books
|
|
// Microsoft OLE DB\OLE DB Programmer's Reference\Part 1 Introduction to OLE DB\
|
|
// Chapter 15: Transactions\Distributed Transactions
|
|
// It is an error to call ITransactionJoin::JoinTransaction if the session is already enlisted in a
|
|
// local transaction. In addition, the provider might require that any existing distributed transactions
|
|
// be committed or aborted before enlisting in a new distributed transaction.
|
|
|
|
|
|
hr = m_pChgRowset1->m_pITxnJoin->JoinTransaction ( pITransaction,
|
|
m_fIsoLevel,
|
|
0,
|
|
NULL);
|
|
if (CHECK(hr, XACT_E_XTIONEXISTS))
|
|
{
|
|
fResults = TRUE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//clean up these txns
|
|
//end the mts coordinated txn, abort it, zombies session
|
|
pITransaction->Abort(NULL, FALSE, FALSE);
|
|
|
|
//unenlist the session from the dead dist txn
|
|
m_pChgRowset1->m_pITxnJoin->JoinTransaction ( NULL,
|
|
ISOLATIONLEVEL_UNSPECIFIED,
|
|
0,
|
|
NULL
|
|
);
|
|
//free objects;
|
|
m_pChgRowset1->FreeJoinTxn();
|
|
if (pITransaction)
|
|
{
|
|
m_pChgRowset1->FreeCoordTxn(pITransaction);
|
|
pITransaction = NULL;
|
|
}
|
|
|
|
ReleaseAllRowsetsAndTxns();
|
|
|
|
return fResults;
|
|
}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(3)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc Illegal Nested Transaction - Local before Join
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCNestedTransactions::Variation_3()
|
|
{
|
|
BOOL fResults = FALSE;
|
|
ITransaction *pITransaction = NULL;
|
|
|
|
//this local transaction should start a local transaction
|
|
if (CHECK(m_pChgRowset1->StartTxn(m_fIsoLevel), S_OK))
|
|
{
|
|
//start coordinated txn & join it
|
|
if (CHECK(m_pChgRowset1->StartCoordTxn(&pITransaction,m_fIsoLevel), TRUE))
|
|
{
|
|
//get transactionjoin transaction object.
|
|
if (CHECK(m_pChgRowset1->GetTxnJoin(), S_OK))
|
|
{
|
|
//coordinated txns are not allowed if local txns are current
|
|
if (CHECK(m_pChgRowset1->m_pITxnJoin->JoinTransaction ( pITransaction,
|
|
m_fIsoLevel,
|
|
0,
|
|
NULL
|
|
), XACT_E_XTIONEXISTS))
|
|
{
|
|
fResults = TRUE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//clean up these txns
|
|
//end the mts coordinated txn, abort it, zombies session
|
|
pITransaction->Abort(NULL, FALSE, FALSE);
|
|
|
|
//unenlist the session from the dead dist txn
|
|
m_pChgRowset1->m_pITxnJoin->JoinTransaction ( NULL,
|
|
ISOLATIONLEVEL_UNSPECIFIED,
|
|
0,
|
|
NULL
|
|
);
|
|
//free objects;
|
|
m_pChgRowset1->FreeJoinTxn();
|
|
if (pITransaction)
|
|
{
|
|
m_pChgRowset1->FreeCoordTxn(pITransaction);
|
|
pITransaction = NULL;
|
|
}
|
|
|
|
ReleaseAllRowsetsAndTxns();
|
|
|
|
return fResults;
|
|
}
|
|
// }}
|
|
|
|
|
|
// }}
|
|
// {{ TCW_TERMINATE_METHOD
|
|
//--------------------------------------------------------------------
|
|
// @mfunc TestCase Termination Routine
|
|
//
|
|
// @rdesc TRUE or FALSE
|
|
//
|
|
BOOL TCNestedTransactions::Terminate()
|
|
{
|
|
// TO DO: Add your own code here
|
|
|
|
// {{ TCW_TERM_BASECLASS_CHECK2
|
|
return(CTxnImmed::Terminate());
|
|
} // }}
|
|
// }}
|
|
// }}
|