13073 lines
370 KiB
C++
13073 lines
370 KiB
C++
//--------------------------------------------------------------------
|
|
// Microsoft OLE DB Test
|
|
//
|
|
// Copyright 1995-2000 Microsoft Corporation.
|
|
//
|
|
// @doc
|
|
//
|
|
// @module IROWRESY.CPP | Source file for IRowsetResynch Test Module.
|
|
//
|
|
|
|
#include "MODStandard.hpp"
|
|
#define DBINITCONSTANTS // Must be defined to initialize constants in OLEDB.H
|
|
#define INITGUID
|
|
#include "stddef.h"
|
|
#include "irowresy.h"
|
|
#include "txnbase.hpp" //Base classes for transacted rowsets
|
|
#include "ExtraLib.h"
|
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Module Values
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// {{ TCW_MODULE_GLOBALS
|
|
DECLARE_MODULE_CLSID = { 0x30f88261, 0xb8b9, 0x11cf, { 0x97, 0x7f, 0x00, 0xaa, 0x00, 0xbd, 0xf9, 0x52 }};
|
|
DECLARE_MODULE_NAME("IRowsetResynch");
|
|
DECLARE_MODULE_OWNER("Microsoft");
|
|
DECLARE_MODULE_DESCRIP("IRowsetRefresh-IRowsetResynch Test Module");
|
|
DECLARE_MODULE_VERSION(840051520);
|
|
// }}
|
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// 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"IRowRefresh/IRowResynch";
|
|
|
|
DBLENGTH g_ulRowSize = 0;
|
|
BOOL g_fDeletedRow = FALSE;
|
|
BOOL g_fBlobFail = FALSE;
|
|
BOOL g_fResynch = FALSE;
|
|
BOOL g_fRefresh = FALSE;
|
|
BOOL g_fVisualCache = FALSE;
|
|
BOOL g_fNOCHANGE = FALSE;
|
|
|
|
|
|
//--------------------------------------------------------------------
|
|
// @func Module level initialization routine
|
|
//
|
|
// @rdesc Success or Failure
|
|
// @flag TRUE | Successful initialization
|
|
// @flag FALSE | Initialization problems
|
|
//
|
|
BOOL ModuleInit(CThisTestModule *pThisTestModule)
|
|
{
|
|
IOpenRowset *pIOpenRowset = NULL;
|
|
IRowset *pIRowset = NULL;
|
|
IRowsetResynch *pIRowsetResynch = NULL;
|
|
IRowsetRefresh *pIRowsetRefresh = NULL;
|
|
DBPROPSET DBPropSetResynch;
|
|
DBPROP DBPropResynch;
|
|
DBPROPSET DBPropSetRefresh;
|
|
DBPROP DBPropRefresh;
|
|
BOOL fResults = TEST_SKIPPED;;
|
|
HRESULT hr = S_OK;
|
|
|
|
//Structs for Resynch set properties
|
|
DBPropSetResynch.guidPropertySet = DBPROPSET_ROWSET;
|
|
DBPropSetResynch.rgProperties = &DBPropResynch;
|
|
DBPropSetResynch.cProperties = 1;
|
|
|
|
DBPropResynch.dwPropertyID = DBPROP_IRowsetResynch;
|
|
DBPropResynch.dwOptions = DBPROPOPTIONS_REQUIRED;
|
|
DBPropResynch.colid = DB_NULLID;
|
|
DBPropResynch.vValue.vt = VT_BOOL;
|
|
V_BOOL(&(DBPropResynch.vValue)) = VARIANT_TRUE;
|
|
|
|
//Structs for Refresh set properties
|
|
DBPropSetRefresh.guidPropertySet = DBPROPSET_ROWSET;
|
|
DBPropSetRefresh.rgProperties = &DBPropRefresh;
|
|
DBPropSetRefresh.cProperties = 1;
|
|
|
|
DBPropRefresh.dwPropertyID = DBPROP_IRowsetRefresh;
|
|
DBPropRefresh.dwOptions = DBPROPOPTIONS_REQUIRED;
|
|
DBPropRefresh.colid = DB_NULLID;
|
|
DBPropRefresh.vValue.vt = VT_BOOL;
|
|
V_BOOL(&(DBPropRefresh.vValue)) = VARIANT_TRUE;
|
|
|
|
if (ModuleCreateDBSession(pThisTestModule))
|
|
{
|
|
//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;
|
|
fResults = TEST_FAIL;
|
|
goto DONE;
|
|
}
|
|
if (FAILED(((CTable *)pThisTestModule->m_pVoid)->CreateTable(NUM_ROWS*2)))
|
|
{
|
|
return FALSE;
|
|
}
|
|
//Fail gracefully and quit module if we don't support openrowset
|
|
if (FAILED(pThisTestModule->m_pIUnknown2->QueryInterface(
|
|
IID_IOpenRowset,
|
|
(void **)&pIOpenRowset)))
|
|
{
|
|
fResults = TEST_SKIPPED;
|
|
goto DONE;
|
|
}
|
|
|
|
//is Resynch supported?
|
|
if ( (pIOpenRowset->OpenRowset( NULL,
|
|
&((CTable *)pThisTestModule->m_pVoid)->GetTableID(),
|
|
NULL,
|
|
IID_IRowset,
|
|
1,
|
|
&DBPropSetResynch,
|
|
(IUnknown **)&pIRowset)== S_OK)
|
|
&&
|
|
(pIRowset->QueryInterface(IID_IRowsetResynch, (void **)&pIRowsetResynch)==S_OK)
|
|
)
|
|
{
|
|
odtLog << L"IRowsetResynch Interface is supported.\n";
|
|
odtLog << L"** WARNING - this interface has been depricated **.\n";
|
|
g_fResynch = TRUE;
|
|
}
|
|
else
|
|
{
|
|
odtLog << L"IRowsetResynch Interface is NOT supported.\n";
|
|
}
|
|
|
|
if(pIRowset)
|
|
{
|
|
pIRowset->Release();
|
|
pIRowset = NULL;
|
|
}
|
|
|
|
//is Refresh supported?
|
|
if ( (pIOpenRowset->OpenRowset( NULL,
|
|
&((CTable *)pThisTestModule->m_pVoid)->GetTableID(),
|
|
NULL,
|
|
IID_IRowset,
|
|
1,
|
|
&DBPropSetRefresh,
|
|
(IUnknown **)&pIRowset)== S_OK)
|
|
&&
|
|
(pIRowset->QueryInterface(IID_IRowsetRefresh, (void **)&pIRowsetRefresh)==S_OK)
|
|
)
|
|
{
|
|
g_fRefresh = TRUE;
|
|
}
|
|
else
|
|
{
|
|
odtLog << L"IRowsetRefresh Interface is NOT supported.\n";
|
|
fResults = TEST_SKIPPED;
|
|
goto DONE;
|
|
}
|
|
|
|
if(pIRowset)
|
|
{
|
|
pIRowset->Release();
|
|
pIRowset = NULL;
|
|
}
|
|
|
|
//test needs one of these to continue
|
|
if (!g_fResynch && !g_fRefresh)
|
|
{
|
|
goto DONE;
|
|
}
|
|
|
|
if(pIRowsetResynch)
|
|
{
|
|
pIRowsetResynch->Release();
|
|
pIRowsetResynch = NULL;
|
|
}
|
|
if(pIRowsetRefresh)
|
|
{
|
|
pIRowsetRefresh->Release();
|
|
pIRowsetRefresh = NULL;
|
|
}
|
|
//check to see if DBROWSTATUS_S_NOCHANGE is returned by the provider when no change is made by resynch
|
|
if (fnNOCHANGE(pIOpenRowset,pThisTestModule))
|
|
{
|
|
g_fNOCHANGE = TRUE;
|
|
}
|
|
|
|
//check to see if the provider has a visual cache
|
|
if (fnVisualCache(pIOpenRowset,pThisTestModule))
|
|
{
|
|
g_fVisualCache = TRUE;
|
|
}
|
|
|
|
//Start with a table with rows. The default will create a non updateable
|
|
//column for the first column, which will be our index. This will ensure
|
|
//that when we change a row from another connection, we are not changing the key,
|
|
//so that in a keyset driven cursor, the changes are visible, and not hidden
|
|
//due to a changed an implicit delete and insert.
|
|
|
|
//Init last actual insert number to last row we inserted
|
|
g_ulLastActualInsert = NUM_ROWS*2;
|
|
|
|
//Init last delete to 0
|
|
g_ulLastActualDelete = 0;
|
|
|
|
//First row in the table is 1
|
|
g_ulFirstRowInTable = 1;
|
|
|
|
//If we made it this far, everything has succeeded
|
|
fResults = TEST_PASS;
|
|
}
|
|
DONE:
|
|
if(pIOpenRowset)
|
|
{
|
|
pIOpenRowset->Release();
|
|
pIOpenRowset = NULL;
|
|
}
|
|
if(pIRowset)
|
|
{
|
|
pIRowset->Release();
|
|
pIRowset = NULL;
|
|
}
|
|
if(pIRowsetResynch)
|
|
{
|
|
pIRowsetResynch->Release();
|
|
pIRowsetResynch = NULL;
|
|
}
|
|
if(pIRowsetRefresh)
|
|
{
|
|
pIRowsetRefresh->Release();
|
|
pIRowsetRefresh = NULL;
|
|
}
|
|
|
|
return fResults;
|
|
}
|
|
|
|
//--------------------------------------------------------------------
|
|
// @func Module level termination routine
|
|
//
|
|
// @rdesc Success or Failure
|
|
// @flag TRUE | Successful initialization
|
|
// @flag FALSE | Initialization problems3
|
|
|
|
//
|
|
BOOL ModuleTerminate(CThisTestModule * pThisTestModule)
|
|
{
|
|
//We still own the table since all of our testcases
|
|
//have only used it and not deleted it.
|
|
if (pThisTestModule->m_pVoid)
|
|
{
|
|
if( ((CTable *)pThisTestModule->m_pVoid)->GetCommandSupOnCTable() )
|
|
((CTable *)pThisTestModule->m_pVoid)->DropTable();
|
|
delete (CTable*)pThisTestModule->m_pVoid;
|
|
pThisTestModule->m_pVoid = NULL;
|
|
}
|
|
|
|
//clean golbas in case test is run twice
|
|
g_ulRowSize = 0;
|
|
g_fDeletedRow = FALSE;
|
|
g_fBlobFail = FALSE;
|
|
g_fResynch = FALSE;
|
|
g_fRefresh = FALSE;
|
|
g_fVisualCache = FALSE;
|
|
g_fNOCHANGE = FALSE;
|
|
|
|
return ModuleReleaseDBSession(pThisTestModule);
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
// TCBase - Class for reusing Test Cases.
|
|
// This is one of the base classes from which all the Test Case
|
|
// classes will inherit. It is used to duplicate test cases, yet
|
|
// maintain some sort of distinct identity for each.
|
|
//
|
|
////////////////////////////////////////////////////////////////////////
|
|
class TCBase
|
|
{
|
|
public:
|
|
//constructor
|
|
TCBase() { SetTestCaseParam(TI_IRowsetResynch); }
|
|
|
|
//Set the m_eTI
|
|
virtual void SetTestCaseParam(ETESTINTERFACE eTestInterface = TI_IRowsetResynch)
|
|
{
|
|
m_eTI = eTestInterface;
|
|
}
|
|
|
|
HRESULT fnInterfaceSupported()
|
|
{
|
|
if(TI_IRowsetResynch==m_eTI)
|
|
{
|
|
if (!g_fResynch)
|
|
{
|
|
return TEST_SKIPPED;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (!g_fRefresh)
|
|
{
|
|
return TEST_SKIPPED;
|
|
}
|
|
}
|
|
return TEST_PASS;
|
|
}
|
|
|
|
BOOL fnIsRowsetUpdatePending(IUnknown *pIUnknown)
|
|
{
|
|
VARIANT_BOOL bValue;
|
|
|
|
//if IRowsetResynch is being used always return TRUE
|
|
//this is because TRUE will cause the test to expect DBROWSTATUS_S_OK or DBROWSTATUS_S_NOCHANGE.
|
|
//FALSE cause the test to expect only DBROWSTATUS_S_NOCHANGE. IRowsetResynch only supports DBROWSTATUS_S_OK.
|
|
//DBROWSTATUS_S_NOCHANGE won't make a difference with IRowsetResynch but it needs to check for DBROWSTATUS_S_OK.
|
|
if (m_eTI==TI_IRowsetResynch)
|
|
{
|
|
return TRUE;
|
|
}
|
|
|
|
if (GetProperty(DBPROP_IRowsetUpdate,DBPROPSET_ROWSET,pIUnknown,&bValue))
|
|
{
|
|
if(bValue==VARIANT_TRUE)
|
|
{
|
|
return TRUE;
|
|
}
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
//@cmember for keeping track of which interface to use
|
|
ETESTINTERFACE m_eTI;
|
|
};
|
|
|
|
|
|
//////////////////////////////////////////////////////////
|
|
//Helper function to determine if a property is supported
|
|
//on the given rowset
|
|
DBPROPSTATUS IsRowsetPropSupported(IUnknown *pRowset,
|
|
DBPROPID PropID)
|
|
{
|
|
IRowsetInfo *pIRowsetInfo = NULL;
|
|
DBPROPIDSET PropIDSet;
|
|
ULONG cDBPropSet = 0;
|
|
DBPROPSET *rgDBPropSet = NULL;
|
|
//This is our default error, even though its not
|
|
//overly reflective of our routine failing
|
|
DBPROPSTATUS dwStatus = DBPROPSTATUS_BADOPTION;
|
|
HRESULT hr = NOERROR;
|
|
IMalloc *pIMalloc = NULL;
|
|
|
|
if (FAILED(CoGetMalloc(1, &pIMalloc)))
|
|
{
|
|
return dwStatus;
|
|
}
|
|
ASSERT(pRowset);
|
|
|
|
PropIDSet.cPropertyIDs = 1;
|
|
PropIDSet.guidPropertySet = DBPROPSET_ROWSET;
|
|
PropIDSet.rgPropertyIDs = &PropID;
|
|
|
|
if (pRowset->QueryInterface(IID_IRowsetInfo, (void **)&pIRowsetInfo) == S_OK)
|
|
{
|
|
if (pIRowsetInfo->GetProperties(1, &PropIDSet, &cDBPropSet, &rgDBPropSet) == S_OK)
|
|
{
|
|
if (rgDBPropSet)
|
|
if (cDBPropSet == 1)
|
|
if (rgDBPropSet[0].rgProperties)
|
|
if (rgDBPropSet[0].cProperties == 1)
|
|
//Get status we'll return (ie, supported, not supported)
|
|
dwStatus = rgDBPropSet[0].rgProperties[0].dwStatus;
|
|
}
|
|
}
|
|
|
|
if(rgDBPropSet)
|
|
{
|
|
if(rgDBPropSet->rgProperties)
|
|
{
|
|
PROVIDER_FREE(rgDBPropSet->rgProperties);
|
|
}
|
|
|
|
PROVIDER_FREE(rgDBPropSet);
|
|
}
|
|
if (pIRowsetInfo)
|
|
{
|
|
pIRowsetInfo->Release();
|
|
pIRowsetInfo = NULL;
|
|
}
|
|
return dwStatus;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////
|
|
//Helper to see if DBROWSTATUS_S_NOCHANGE is returned by
|
|
//the provider when no change is made by resynch
|
|
BOOL fnNOCHANGE( IOpenRowset *pIOpenRowset,
|
|
CThisTestModule *pThisTestModule)
|
|
{
|
|
IRowsetRefresh *pIRowsetRefresh= NULL;
|
|
IRowset *pIRowset = NULL;
|
|
const ULONG cProps = 1;
|
|
DBPROPSET DBPropSet;
|
|
DBPROP DBProp[cProps];
|
|
DBORDINAL cRowsetCols;
|
|
const ULONG cRows = 1;
|
|
HROW rghRows[cRows];
|
|
HROW *phRows = rghRows;
|
|
DBCOUNTITEM cRowsObtained = 1;
|
|
DBCOUNTITEM cRowsResynched = 0;
|
|
DBROWSTATUS *rgReRowStatus = NULL;
|
|
HROW *rghReRows = NULL;
|
|
BOOL fNoChange = FALSE;
|
|
|
|
//if RefreshData is NOT supported then leave this global flag set as flag
|
|
//cause ResynchData does not support DBROWSTATUS_S_NOCHANGE
|
|
if (g_fRefresh)
|
|
{
|
|
//Struct for set properties
|
|
DBPropSet.guidPropertySet = DBPROPSET_ROWSET;
|
|
DBPropSet.rgProperties = DBProp;
|
|
DBPropSet.cProperties = cProps;
|
|
|
|
DBProp[0].dwPropertyID = DBPROP_IRowsetRefresh;
|
|
DBProp[0].dwOptions = 0;
|
|
DBProp[0].colid = DB_NULLID;
|
|
DBProp[0].vValue.vt = VT_BOOL;
|
|
V_BOOL(&(DBProp[0].vValue)) = VARIANT_TRUE;
|
|
|
|
//get a rowset
|
|
((CTable *)pThisTestModule->m_pVoid)->CreateRowset( USE_OPENROWSET,
|
|
IID_IRowset,
|
|
1,
|
|
&DBPropSet,
|
|
(IUnknown**)&pIRowset,
|
|
NULL,
|
|
&cRowsetCols,
|
|
NULL,
|
|
0,
|
|
NULL,
|
|
pIOpenRowset);
|
|
|
|
//get the first row
|
|
TESTC_(pIRowset->RestartPosition(NULL), S_OK);
|
|
TESTC_(pIRowset->GetNextRows(NULL, 0, 1, &cRowsObtained, &phRows),S_OK);
|
|
|
|
//get refresh(or resynch) from rowset
|
|
if (!VerifyInterface(pIRowset, IID_IRowsetRefresh, ROWSET_INTERFACE, (IUnknown **)&pIRowsetRefresh))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
|
|
//refresh the data from the rowset
|
|
TESTC_(pIRowsetRefresh->RefreshVisibleData(DB_NULL_HCHAPTER,1, &phRows[0], TRUE, &cRowsResynched, &rghReRows, &rgReRowStatus),S_OK);
|
|
|
|
//Free the row for the GetNextRows call
|
|
TESTC_(pIRowset->ReleaseRows(1, phRows, NULL, NULL, NULL), S_OK);
|
|
|
|
if (rgReRowStatus[cRowsResynched-1]==DBROWSTATUS_S_NOCHANGE)
|
|
{
|
|
fNoChange = TRUE;
|
|
}
|
|
//else
|
|
//{
|
|
// fNoChange = FALSE; //FASLE is default
|
|
//}
|
|
}
|
|
CLEANUP:
|
|
SAFE_RELEASE(pIRowset);
|
|
SAFE_RELEASE(pIRowsetRefresh);
|
|
|
|
PROVIDER_FREE(rgReRowStatus);
|
|
PROVIDER_FREE(rghReRows);
|
|
|
|
return fNoChange;
|
|
}
|
|
|
|
|
|
//////////////////////////////////////////////////////////
|
|
//Helper to see if the provider has a visual cache
|
|
BOOL fnVisualCache(IOpenRowset *pIOpenRowset,
|
|
CThisTestModule *pThisTestModule)
|
|
{
|
|
HACCESSOR hAccessor1 = DB_NULL_HACCESSOR;
|
|
HACCESSOR hAccessor2 = DB_NULL_HACCESSOR;
|
|
IAccessor *pIAccessor1 = NULL;
|
|
IAccessor *pIAccessor2 = NULL;
|
|
DBBINDING *rgBindings = NULL;
|
|
DBCOUNTITEM cBindings = 0;
|
|
ITransactionLocal *pITransactionLocal = NULL;
|
|
IRowsetChange *pIRowsetChange = NULL;
|
|
IRowsetRefresh *pIRowsetRefresh= NULL;
|
|
IRowsetResynch *pIRowsetResynch= NULL;
|
|
IRowset *pIRowset1 = NULL;
|
|
IRowset *pIRowset2 = NULL;
|
|
const ULONG cProps = 4;
|
|
DBPROPSET DBPropSet;
|
|
DBPROP DBProp[cProps];
|
|
HRESULT hr = S_OK;
|
|
BYTE *pData = NULL;
|
|
DB_LORDINAL *rgTableColOrds;
|
|
DBORDINAL cRowsetCols;
|
|
const ULONG cRows = 1;
|
|
HROW rghRows1[cRows];
|
|
HROW *phRows1 = rghRows1;
|
|
HROW rghRows2[cRows];
|
|
HROW *phRows2 = rghRows2;
|
|
BOOL fFound = FALSE;
|
|
DBCOUNTITEM cRowsObtained = 1;
|
|
IMalloc *pIMalloc = NULL;
|
|
DBLENGTH cRowSize = 0;
|
|
|
|
//If we can't get our memory allocator, we're in trouble anyway, so assert
|
|
CoGetMalloc(MEMCTX_TASK, &pIMalloc);
|
|
ASSERT(pIMalloc);
|
|
|
|
//Struct for set properties
|
|
DBPropSet.guidPropertySet = DBPROPSET_ROWSET;
|
|
DBPropSet.rgProperties = DBProp;
|
|
DBPropSet.cProperties = cProps;
|
|
|
|
DBProp[0].dwPropertyID = DBPROP_IRowsetChange;
|
|
DBProp[0].dwOptions = DBPROPOPTIONS_REQUIRED;
|
|
DBProp[0].colid = DB_NULLID;
|
|
DBProp[0].vValue.vt = VT_BOOL;
|
|
V_BOOL(&(DBProp[0].vValue)) = VARIANT_TRUE;
|
|
|
|
DBProp[1].dwPropertyID = DBPROP_UPDATABILITY;
|
|
DBProp[1].dwOptions = 0;
|
|
DBProp[1].colid = DB_NULLID;
|
|
DBProp[1].vValue.vt = VT_I4;
|
|
DBProp[1].vValue.lVal = DBPROPVAL_UP_CHANGE | DBPROPVAL_UP_DELETE | DBPROPVAL_UP_INSERT;
|
|
|
|
if(g_fRefresh)
|
|
{
|
|
DBProp[2].dwPropertyID = DBPROP_IRowsetRefresh;
|
|
DBProp[2].dwOptions = 0;
|
|
DBProp[2].colid = DB_NULLID;
|
|
DBProp[2].vValue.vt = VT_BOOL;
|
|
V_BOOL(&(DBProp[2].vValue)) = VARIANT_TRUE;
|
|
}
|
|
else
|
|
{
|
|
DBProp[2].dwPropertyID = DBPROP_IRowsetResynch;
|
|
DBProp[2].dwOptions = 0;
|
|
DBProp[2].colid = DB_NULLID;
|
|
DBProp[2].vValue.vt = VT_BOOL;
|
|
V_BOOL(&(DBProp[2].vValue)) = VARIANT_TRUE;
|
|
}
|
|
|
|
DBProp[3].dwPropertyID = DBPROP_OTHERUPDATEDELETE;
|
|
DBProp[3].dwOptions = DBPROPOPTIONS_REQUIRED;
|
|
DBProp[3].colid = DB_NULLID;
|
|
DBProp[3].vValue.vt = VT_BOOL;
|
|
V_BOOL(&(DBProp[3].vValue)) = VARIANT_TRUE;
|
|
|
|
//Get IRowset on the object
|
|
if (!VerifyInterface(pIOpenRowset, IID_ITransactionLocal, SESSION_INTERFACE, (IUnknown **)&pITransactionLocal))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
|
|
hr=pITransactionLocal->StartTransaction(ISOLATIONLEVEL_READCOMMITTED, 0, NULL, NULL);
|
|
|
|
//get 2 rowsets
|
|
((CTable *)pThisTestModule->m_pVoid)->CreateRowset( USE_OPENROWSET,
|
|
IID_IRowset,
|
|
1,
|
|
&DBPropSet,
|
|
(IUnknown**)&pIRowset1,
|
|
NULL,
|
|
&cRowsetCols,
|
|
&rgTableColOrds,
|
|
0,
|
|
NULL,
|
|
pIOpenRowset);
|
|
|
|
PROVIDER_FREE(rgTableColOrds);
|
|
|
|
((CTable *)pThisTestModule->m_pVoid)->CreateRowset( USE_OPENROWSET,
|
|
IID_IRowset,
|
|
1,
|
|
&DBPropSet,
|
|
(IUnknown**)&pIRowset2,
|
|
NULL,
|
|
&cRowsetCols,
|
|
&rgTableColOrds,
|
|
0,
|
|
NULL,
|
|
pIOpenRowset);
|
|
|
|
//Get IRowset on the object
|
|
if (!VerifyInterface(pIRowset1, IID_IAccessor, ROWSET_INTERFACE, (IUnknown **)&pIAccessor1))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
|
|
//Get IRowset on the object
|
|
if (!VerifyInterface(pIRowset2, IID_IAccessor, ROWSET_INTERFACE, (IUnknown **)&pIAccessor2))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
|
|
TESTC_(GetAccessorAndBindings( pIAccessor1,
|
|
DBACCESSOR_ROWDATA,
|
|
&hAccessor1,
|
|
&rgBindings,
|
|
&cBindings,
|
|
&cRowSize,
|
|
DBPART_VALUE | DBPART_LENGTH | DBPART_STATUS,
|
|
ALL_COLS_BOUND,
|
|
FORWARD,
|
|
NO_COLS_BY_REF,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
DBTYPE_EMPTY,
|
|
0,
|
|
NULL,
|
|
NULL,
|
|
NO_COLS_OWNED_BY_PROV,
|
|
DBPARAMIO_NOTPARAM,
|
|
NO_BLOB_COLS),S_OK);
|
|
|
|
|
|
//alloc here just so test has it to free for ReleaseInputBindingsMemory
|
|
pData = (BYTE *)PROVIDER_ALLOC(cRowSize);
|
|
//Cleanup any out of line memory allocated in FillInputBindings and pData
|
|
ReleaseInputBindingsMemory(cBindings, rgBindings, pData, TRUE);
|
|
if (rgBindings)
|
|
{
|
|
PROVIDER_FREE(rgBindings);
|
|
}
|
|
pData = NULL;
|
|
|
|
TESTC_(GetAccessorAndBindings( pIAccessor2,
|
|
DBACCESSOR_ROWDATA,
|
|
&hAccessor2,
|
|
&rgBindings,
|
|
&cBindings,
|
|
NULL,
|
|
DBPART_VALUE | DBPART_LENGTH | DBPART_STATUS,
|
|
ALL_COLS_BOUND,
|
|
FORWARD,
|
|
NO_COLS_BY_REF,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
DBTYPE_EMPTY,
|
|
0,
|
|
NULL,
|
|
NULL,
|
|
NO_COLS_OWNED_BY_PROV,
|
|
DBPARAMIO_NOTPARAM,
|
|
NO_BLOB_COLS),S_OK);
|
|
|
|
//Set data for all columns
|
|
TESTC_(FillInputBindings( ((CTable *)pThisTestModule->m_pVoid),
|
|
DBACCESSOR_ROWDATA,
|
|
cBindings,
|
|
rgBindings,
|
|
&pData,
|
|
98,
|
|
((CTable *)pThisTestModule->m_pVoid)->CountColumnsOnTable(),
|
|
rgTableColOrds), S_OK);
|
|
|
|
//Get IRowsetChange on the object
|
|
if (!VerifyInterface(pIRowset1, IID_IRowsetChange, ROWSET_INTERFACE, (IUnknown **)&pIRowsetChange))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
|
|
//get the first row through the 1st rowset
|
|
pIRowset1->RestartPosition(NULL);
|
|
|
|
TESTC_(pIRowset1->GetNextRows(NULL, 0, 1, &cRowsObtained, &phRows1),S_OK);
|
|
|
|
//get the first row through the 2nd rowset
|
|
TESTC_(pIRowset2->RestartPosition(NULL), S_OK);
|
|
TESTC_(pIRowset2->GetNextRows(NULL, 0, 1, &cRowsObtained, &phRows2),S_OK);
|
|
|
|
//change the data through the first rowset
|
|
TESTC_(pIRowsetChange->SetData(phRows1[0], hAccessor1, pData), S_OK);
|
|
TESTC_(pIRowset1->ReleaseRows(cRowsObtained, phRows1, NULL, NULL, NULL), S_OK);
|
|
|
|
//get refresh(or resynch) from rowset2
|
|
if(g_fRefresh)
|
|
{
|
|
if (!VerifyInterface(pIRowset2, IID_IRowsetRefresh, ROWSET_INTERFACE, (IUnknown **)&pIRowsetRefresh))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (!VerifyInterface(pIRowset2, IID_IRowsetResynch, ROWSET_INTERFACE, (IUnknown **)&pIRowsetResynch))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
}
|
|
|
|
//get the visible data from the 2nd rowset
|
|
if (g_fRefresh)
|
|
{
|
|
TESTC_(pIRowsetRefresh->GetLastVisibleData(phRows2[0], hAccessor2, pData),S_OK);
|
|
}
|
|
else
|
|
{
|
|
TESTC_(pIRowsetResynch->GetVisibleData(phRows2[0], hAccessor2, pData),S_OK);
|
|
}
|
|
|
|
//Check this row against ulRowNum, free pData when done
|
|
if (CompareData(((CTable *)pThisTestModule->m_pVoid)->CountColumnsOnTable(), rgTableColOrds,
|
|
98, pData, cBindings, rgBindings,
|
|
((CTable *)pThisTestModule->m_pVoid), pIMalloc, PRIMARY,
|
|
COMPARE_FREE, COMPARE_UNTIL_ERROR))
|
|
{
|
|
//We found the row, woo-hoo.
|
|
fFound = TRUE;
|
|
}
|
|
//Free the row for this GetNextRows call
|
|
TESTC_(pIRowset2->ReleaseRows(1, phRows2, NULL, NULL, NULL), S_OK);
|
|
CLEANUP:
|
|
//clean up any changes this little kludge messed on the back end
|
|
hr=pITransactionLocal->Abort(NULL,FALSE,FALSE);
|
|
|
|
//Cleanup any out of line memory allocated in FillInputBindings and pData
|
|
ReleaseInputBindingsMemory(cBindings, rgBindings, pData, TRUE);
|
|
if (rgBindings)
|
|
{
|
|
PROVIDER_FREE(rgBindings);
|
|
}
|
|
PROVIDER_FREE(rgTableColOrds);
|
|
|
|
//Release accessor1
|
|
if ((hAccessor1 != DB_NULL_HACCESSOR) && pIAccessor1)
|
|
{
|
|
CHECK(pIAccessor1->ReleaseAccessor(hAccessor1, NULL), S_OK);
|
|
hAccessor1 = DB_NULL_HACCESSOR;
|
|
}
|
|
//Release accessor2
|
|
if ((hAccessor2 != DB_NULL_HACCESSOR) && pIAccessor2)
|
|
{
|
|
CHECK(pIAccessor2->ReleaseAccessor(hAccessor2, NULL), S_OK);
|
|
hAccessor2 = DB_NULL_HACCESSOR;
|
|
}
|
|
|
|
|
|
SAFE_RELEASE(pITransactionLocal);
|
|
SAFE_RELEASE(pIAccessor1);
|
|
SAFE_RELEASE(pIAccessor2);
|
|
SAFE_RELEASE(pIRowset1);
|
|
SAFE_RELEASE(pIRowset2);
|
|
SAFE_RELEASE(pIRowsetChange);
|
|
SAFE_RELEASE(pIRowsetRefresh);
|
|
SAFE_RELEASE(pIRowsetResynch);
|
|
|
|
SAFE_RELEASE(pIMalloc);
|
|
//if found - no visualcache
|
|
//if not found - there is a visible cache
|
|
return !fFound;
|
|
}
|
|
|
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Base Class Declarations
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
|
|
|
|
//////////////////////////////////////////////////////////////
|
|
//Base class for all IRowResy test cases
|
|
//////////////////////////////////////////////////////////////
|
|
class CResynchRefresh : public CTxnImmed, public TCBase
|
|
{
|
|
// @access public
|
|
public:
|
|
//@cmember Tells if long data can be supported on this rowset
|
|
BLOBTYPE m_fBindLongData;
|
|
//@cmember Accessor handle for Read Only Rowset
|
|
HACCESSOR m_hROAccessor;
|
|
//@cmember Accessor handle for Changeable Rowset
|
|
HACCESSOR m_hChgAccessor;
|
|
//@cmember Accessor handle for Changeable Rowset
|
|
HACCESSOR m_hChgAccessor2;
|
|
//@cmember Number of bindings in the Accessors
|
|
DBCOUNTITEM m_cBindings;
|
|
//@cmember Array of bindings for the Accessors
|
|
DBBINDING *m_rgBindings;
|
|
//@cmember Row size for one row using the Accessors
|
|
DBLENGTH m_cbRowSize;
|
|
//@cmember Memory to put address of cached data
|
|
BYTE *m_pRowsetData;
|
|
//@cmember Memory to put address of visible data
|
|
BYTE *m_pVisibleData;
|
|
//@cmember Memory to put address of newly resynch'd rowset data
|
|
BYTE *m_pResynchRowsetData;
|
|
//@cmember Memory to put address of newly resynch'd visible data
|
|
BYTE *m_pResynchVisibleData;
|
|
//@cmember Flag indicating if the row change is successful
|
|
BOOL m_fNoChange;
|
|
//@cmember Flag indicating if pass by ref accessors are supported
|
|
BOOL m_fPassByRef;
|
|
//@cmember Flag indicating if strong identity is supported
|
|
BOOL m_fStrongIdentity;
|
|
//@cmember Memory for count of rows resynched
|
|
DBCOUNTITEM m_cRowsResynched;
|
|
//@cmember Memory for array of hrows Resynched
|
|
HROW *m_rghRowsResynched;
|
|
//@cmember Memory for array of row status
|
|
DBROWSTATUS *m_rgRowStatus;
|
|
//@cmember Flag indicating if CreateResynchObjects should
|
|
//create accessors with BLOBS bound if it is supported.
|
|
//Initialized to FALSE.
|
|
BOOL m_fRequestLongDataIfSupported;
|
|
|
|
|
|
//@cmember IRowsetResynch interface on Read Only Rowset
|
|
IRowsetResynch *m_pROIRowsetResynch;
|
|
//@cmember IRowsetResynch interface on Changeable Rowset
|
|
IRowsetResynch *m_pChgIRowsetResynch;
|
|
|
|
//@cmember IRowsetRefresh interface on Read Only Rowset
|
|
IRowsetRefresh *m_pROIRowsetRefresh;
|
|
//@cmember IRowsetRefresh interface on Changeable Rowset
|
|
IRowsetRefresh *m_pChgIRowsetRefresh;
|
|
|
|
//@cmember IRowset interface used to free hRows
|
|
IRowset *m_pChgIRowset;
|
|
//@cmember IRowset interface used to free hRows
|
|
IRowset *m_pROIRowset;
|
|
|
|
|
|
//@cmember CTOR
|
|
//CGetSession(WCHAR* pwszTestCaseName = INVALID(WCHAR*));
|
|
CResynchRefresh(LPWSTR tcName) : CTxnImmed(tcName)
|
|
{
|
|
m_pROIRowsetResynch = NULL;
|
|
m_pChgIRowsetResynch = NULL;
|
|
m_pROIRowsetRefresh = NULL;
|
|
m_pChgIRowsetRefresh = NULL;
|
|
m_pChgIRowset = NULL;
|
|
m_pROIRowset = NULL;
|
|
m_hROAccessor = DB_NULL_HACCESSOR;
|
|
m_hChgAccessor = DB_NULL_HACCESSOR;
|
|
m_hChgAccessor2 = DB_NULL_HACCESSOR;
|
|
m_cBindings = 0;
|
|
m_rgBindings = NULL;
|
|
m_cbRowSize = 0;
|
|
m_pRowsetData = NULL;
|
|
m_pVisibleData = NULL;
|
|
m_pResynchRowsetData = NULL;
|
|
m_pResynchVisibleData = NULL;
|
|
m_fNoChange = FALSE;
|
|
m_fPassByRef = FALSE;
|
|
m_fBindLongData = NO_BLOB_COLS;
|
|
m_fRequestLongDataIfSupported = FALSE;
|
|
};
|
|
|
|
//Allocs memory for data buffers
|
|
BOOL AllocDataBuffers(DBLENGTH cbRowSize);
|
|
|
|
//Frees memory for data buffers
|
|
void FreeBuffers(DBLENGTH cbRowSize);
|
|
|
|
//@cmember Frees any memory associated with the output params of ResynchRows
|
|
void FreeOutParams();
|
|
|
|
//@cmember Compares the outparams to make sure they contain the right values
|
|
void CompareOutParams(DBCOUNTITEM cExpectedRows, HROW * rgExpectedhRows);
|
|
|
|
//@cmember Checks that the output parameters are properly set when an error occurs
|
|
void CheckOutParamsAreNulled();
|
|
|
|
//@cmember Does generic IRowsetResynch testing -- to be called with different
|
|
//property settings
|
|
int TestResynchRefresh(ETESTROWSETTYPE eTestRowsetType);
|
|
|
|
//@cmember Calls ChangeUnderlyingRowAndGetHrow and GetDataBuffers
|
|
//retrieves visible data and cached data (via GetData) for that row
|
|
BOOL GenerateResynchData( CTxnRowset *pFirstTxnRowset,
|
|
ISOLEVEL fIsoLevel,
|
|
HACCESSOR hAccessor,
|
|
DBBINDING *rgBindings = NULL,
|
|
DBCOUNTITEM cBindings = 0);
|
|
|
|
//@cmember Determines if pass by ref accessors are supported
|
|
void DetermineProps();
|
|
|
|
//@cmember checks property status for required properties after CreatRowsetObject()
|
|
BOOL DidPropsFail(CTxnRowset * pRowset);
|
|
|
|
//@cmember Changes the underlying row via another transaction, and returns
|
|
//the hRow corresponding to that row, before the cache has been resynch'd.
|
|
//If phRow is NULL, the hRow is released and is not passed to the caller
|
|
BOOL ChangeUnderlyingRowAndGetHrow( CTxnRowset *pFirstTxnRowset,
|
|
ISOLEVEL fIsoLevel,
|
|
HROW *phRow);
|
|
|
|
//@cmember Does GetVisibleData and GetData on the cached row. Then
|
|
// does ResynchRows and GetData on the resynch'd row.
|
|
BOOL GetDataBuffers(CTxnRowset *pFirstTxnRowset,
|
|
ISOLEVEL fIsoLevel,
|
|
HACCESSOR hAccessor,
|
|
HROW hRow,
|
|
DBBINDING *rgBindings = NULL,
|
|
DBCOUNTITEM cBindings = 0);
|
|
|
|
//@cmember Verifies visible data buffer based on fSeeVisibleData &
|
|
//fSeeVisibleResynchedData flags and GetData cached buffer based on
|
|
//fSeeRowsetData flag. If bindings are not passed, the data members
|
|
//m_cBindings and m_rgBindings are used for determining buffer format.
|
|
//Note that VERIFY_IGNORE is used when we are using BLOB columns,
|
|
//we can never get cached BLOB values. So VERIFY_IGNORE is placed for
|
|
//all fSeeRowseteData where any BLOBS are bound, and also whereever
|
|
//VERIFY_OLD is normally expected and BLOBS are bound.
|
|
BOOL VerifyData(EVERIFY fSeeVisibleResynchedData,
|
|
EVERIFY fSeeVisibleData,
|
|
EVERIFY fSeeRowsetData = VERIFY_OLD,
|
|
EVERIFY fSeeRowsetResynchedData = VERIFY_OLD,
|
|
ULONG ulOldRowNum = 0,
|
|
ULONG ulNewRowNum = 0,
|
|
DBCOUNTITEM cVerifyBindings = 0,
|
|
DBBINDING *rgVerifyBindings = NULL);
|
|
|
|
//@cmember Sets all correct properties for testing rowsets with IRowsetResynch
|
|
BOOL SetAllProperties( CTxnRowset *pTxnRowset,
|
|
ULONG cAdditionalProps,
|
|
DBPROP *rgAdditionalProps);
|
|
|
|
//@cmember Changes the rowsets created in CResynchRefresh::Init to not support
|
|
//some properties, as well as to support the properties passed in.
|
|
//Also if fBindLongData is TRUE, this is set in the rowset objects
|
|
//so that they create accessors with long columns bound
|
|
BOOL ChangeProperties(ULONG cAddProps, DBPROP * rgAddProps, ULONG cRemoveProps, DBPROPID * rgRemoveProps,
|
|
DBPROPOPTIONS * rgPropOptions, BLOBTYPE fBindLongData = NO_BLOB_COLS);
|
|
|
|
//@cmember Starts both Chg1 and RO1 rowsets in specificied transaction isolation level
|
|
HRESULT StartTxns( ISOLEVEL fIsoLevel);
|
|
|
|
//@cmember Ends both Chg1 and RO1 rowsets' transactions by doing a non retaining commit
|
|
BOOL EndTxns(BOOL fAbort = FALSE);
|
|
|
|
//@cmember creates all objects needed for CResynchRefresh::Init
|
|
BOOL CreateResynchObjects(ETESTINTERFACE eTI);
|
|
|
|
//@cmember Releases all objects created by CreateResynchObjects
|
|
void ReleaseResynchObjects();
|
|
|
|
//@cmember ResynchRows\RefreshVisibleData wrapper
|
|
HRESULT ResynchRefresh( HCHAPTER hChapter,
|
|
DBCOUNTITEM cRows,
|
|
const HROW rghRows[],
|
|
BOOL fOverwrite,
|
|
DBCOUNTITEM *pcRowsRefreshed,
|
|
HROW **prghRowsRefreshed,
|
|
DBROWSTATUS **prgRowStatus,
|
|
BOOL fRO);
|
|
|
|
//@cmember Get(Last)VisibleData wrapper
|
|
HRESULT GetLastVisibleData( HROW hRow,
|
|
HACCESSOR hAccessor,
|
|
void *pData,
|
|
BOOL fRO);
|
|
|
|
//@cmember Init
|
|
BOOL Init(ETESTINTERFACE eTI);
|
|
//@cmember Terminate
|
|
BOOL Terminate();
|
|
};
|
|
|
|
|
|
//--------------------------------------------------------------------
|
|
// @mfunc Init
|
|
//
|
|
// @rdesc TRUE or FALSE
|
|
//
|
|
BOOL CResynchRefresh::Init(ETESTINTERFACE eTI)
|
|
{
|
|
const ULONG cAdditionalProps = 2;
|
|
DBPROP rgAdditionalProps[cAdditionalProps];
|
|
|
|
//set a which interface to use in the class
|
|
m_eTI=eTI;
|
|
|
|
if(TI_IRowsetResynch==eTI)
|
|
{
|
|
rgAdditionalProps[0].dwPropertyID = DBPROP_IRowsetResynch;
|
|
rgAdditionalProps[0].dwOptions = 0;
|
|
rgAdditionalProps[0].colid = DB_NULLID;
|
|
rgAdditionalProps[0].vValue.vt = VT_BOOL;
|
|
V_BOOL(&(rgAdditionalProps[0].vValue)) = VARIANT_TRUE;
|
|
|
|
rgAdditionalProps[1].dwPropertyID = DBPROP_CANHOLDROWS;
|
|
rgAdditionalProps[1].dwOptions = 0;
|
|
rgAdditionalProps[1].colid = DB_NULLID;
|
|
rgAdditionalProps[1].vValue.vt = VT_BOOL;
|
|
V_BOOL(&(rgAdditionalProps[1].vValue)) = VARIANT_TRUE;
|
|
}
|
|
else
|
|
{
|
|
rgAdditionalProps[0].dwPropertyID = DBPROP_IRowsetRefresh;
|
|
rgAdditionalProps[0].dwOptions = 0;
|
|
rgAdditionalProps[0].colid = DB_NULLID;
|
|
rgAdditionalProps[0].vValue.vt = VT_BOOL;
|
|
V_BOOL(&(rgAdditionalProps[0].vValue)) = VARIANT_TRUE;
|
|
|
|
rgAdditionalProps[1].dwPropertyID = DBPROP_CANHOLDROWS;
|
|
rgAdditionalProps[1].dwOptions = 0;
|
|
rgAdditionalProps[1].colid = DB_NULLID;
|
|
rgAdditionalProps[1].vValue.vt = VT_BOOL;
|
|
V_BOOL(&(rgAdditionalProps[1].vValue)) = VARIANT_TRUE;
|
|
}
|
|
|
|
if (CTxnImmed::Init())
|
|
{
|
|
//Set properties for this rowset, including those needed for IRowsetResynch / IRowsetRefresh
|
|
if (SetAllProperties(m_pChgRowset2, cAdditionalProps, rgAdditionalProps))
|
|
{
|
|
//Set properties for this rowset, including those needed for IRowsetResynch / IRowsetRefresh
|
|
if (SetAllProperties(m_pChgRowset1, cAdditionalProps, rgAdditionalProps))
|
|
{
|
|
//Now do the same thing for the read only rowset
|
|
if (SetAllProperties(m_pRORowset1, cAdditionalProps, rgAdditionalProps))
|
|
{
|
|
//Make rowsets and accessors and get IRowsetResynch/IRowsetRefresh interfaces on the
|
|
//first changeable rowset and the read only rowset
|
|
if (CreateResynchObjects(eTI))
|
|
{
|
|
//Find out what type of property support we have
|
|
DetermineProps();
|
|
return TRUE;
|
|
}
|
|
else
|
|
{
|
|
//This is the only valid reason for our object creation to fail.
|
|
//NOTE this is also the only place we allow the funciton to fail
|
|
//If we get past this function in init, we know the support is there and it
|
|
//should always succeed after that.
|
|
odtLog << wszResynchNotSupported;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
//Allocs memory for data buffers
|
|
//If buffers already exists, it frees and reallocs the new size given
|
|
BOOL CResynchRefresh::AllocDataBuffers(DBLENGTH cbRowSize)
|
|
{
|
|
//Free any existing buffers
|
|
PROVIDER_FREE(m_pVisibleData);
|
|
PROVIDER_FREE(m_pRowsetData);
|
|
PROVIDER_FREE(m_pResynchRowsetData);
|
|
PROVIDER_FREE(m_pResynchVisibleData);
|
|
|
|
m_pVisibleData = (BYTE *)PROVIDER_ALLOC(cbRowSize);
|
|
m_pRowsetData = (BYTE *)PROVIDER_ALLOC(cbRowSize);
|
|
m_pResynchRowsetData = (BYTE *)PROVIDER_ALLOC(cbRowSize);
|
|
m_pResynchVisibleData = (BYTE *)PROVIDER_ALLOC(cbRowSize);
|
|
|
|
memset(m_pVisibleData, 0, (size_t)cbRowSize);
|
|
memset(m_pRowsetData, 0, (size_t)cbRowSize);
|
|
memset(m_pResynchRowsetData, 0, (size_t)cbRowSize);
|
|
memset(m_pResynchVisibleData, 0, (size_t)cbRowSize);
|
|
|
|
return m_pVisibleData && m_pRowsetData && m_pResynchRowsetData && m_pResynchVisibleData;
|
|
}
|
|
//--------------------------------------------------------------------
|
|
//Frees memory for m_pVisibleData, m_pResynchRowsetData and m_pRowsetData buffers
|
|
void CResynchRefresh::FreeBuffers(DBLENGTH cbRowSize)
|
|
{
|
|
//Free any existing buffers
|
|
PROVIDER_FREE(m_pVisibleData);
|
|
PROVIDER_FREE(m_pRowsetData);
|
|
PROVIDER_FREE(m_pResynchRowsetData);
|
|
PROVIDER_FREE(m_pResynchVisibleData);
|
|
|
|
if (m_pVisibleData)
|
|
{
|
|
memset(m_pVisibleData, 0, (size_t)cbRowSize);
|
|
}
|
|
if (m_pRowsetData)
|
|
{
|
|
memset(m_pRowsetData, 0, (size_t)cbRowSize);
|
|
}
|
|
if (m_pResynchRowsetData)
|
|
{
|
|
memset(m_pResynchRowsetData, 0, (size_t)cbRowSize);
|
|
}
|
|
if (m_pResynchVisibleData)
|
|
{
|
|
memset(m_pResynchVisibleData, 0, (size_t)cbRowSize);
|
|
}
|
|
}
|
|
//--------------------------------------------------------------------
|
|
// @mfunc FreeOutParams
|
|
//
|
|
// @rdesc TRUE or FALSE
|
|
//
|
|
void CResynchRefresh::FreeOutParams()
|
|
{
|
|
if (m_rghRowsResynched)
|
|
{
|
|
if (m_rghRowsResynched == (HROW*) JUNK_PTR)
|
|
m_rghRowsResynched = NULL;
|
|
else
|
|
PROVIDER_FREE(m_rghRowsResynched);
|
|
}
|
|
if (m_rgRowStatus)
|
|
{
|
|
if (m_rgRowStatus == (DBROWSTATUS*) JUNK_PTR)
|
|
m_rgRowStatus = NULL;
|
|
else
|
|
PROVIDER_FREE(m_rgRowStatus);
|
|
}
|
|
}
|
|
|
|
|
|
//--------------------------------------------------------------------
|
|
// @mfunc CheckOutParamsAreNulled
|
|
//
|
|
// @rdesc TRUE or FALSE
|
|
void CResynchRefresh::CheckOutParamsAreNulled()
|
|
{
|
|
//Params should be in this state when a fatal error such as E_FAIL
|
|
//is returned, or when no rows exist to be resynch'd.
|
|
COMPARE(m_cRowsResynched, 0);
|
|
COMPARE(m_rghRowsResynched, NULL);
|
|
COMPARE(m_rgRowStatus, NULL);
|
|
}
|
|
|
|
//--------------------------------------------------------------------
|
|
// @mfunc CompareOutParams
|
|
// Note that rgExpectedhRows is compared with
|
|
// m_rghRowsResych'd unless rgExpectedhRows is NULL, and cExpectedRows
|
|
// is compared with m_cRowsResynch'd.
|
|
//
|
|
// @rdesc TRUE or FALSE
|
|
|
|
void CResynchRefresh::CompareOutParams(DBCOUNTITEM cExpectedRows, HROW * rgExpectedhRows)
|
|
{
|
|
//Make sure the number of rows attempted to be resynched
|
|
//is correct
|
|
COMPARE(cExpectedRows, m_cRowsResynched);
|
|
|
|
//User expects this set of hRows to match the output param prghRowsResynched
|
|
if (rgExpectedhRows)
|
|
{
|
|
while (cExpectedRows)
|
|
{
|
|
//Make our 1-based count a 0-based index into the hrow array
|
|
cExpectedRows--;
|
|
|
|
COMPARE(rgExpectedhRows[cExpectedRows], m_rghRowsResynched[cExpectedRows]);
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
|
|
//--------------------------------------------------------------------
|
|
// @mfunc DetermineProps
|
|
//
|
|
// @rdesc TRUE or FALSE
|
|
//
|
|
void CResynchRefresh::DetermineProps()
|
|
{
|
|
IDBProperties *pIDBProp = NULL;
|
|
IRowsetInfo *pIRowInfo = NULL;
|
|
DBPROPIDSET PropIDSet;
|
|
PROPID PropID;
|
|
ULONG cPropSets = 0;
|
|
DBPROPSET *rgPropSets = NULL;
|
|
|
|
PropID = DBPROP_BYREFACCESSORS;
|
|
PropIDSet.guidPropertySet = DBPROPSET_DATASOURCEINFO;
|
|
PropIDSet.cPropertyIDs = 1;
|
|
PropIDSet.rgPropertyIDs = &PropID;
|
|
|
|
|
|
//Find out if PASS BY REF Accessors are supported
|
|
if (VerifyInterface(m_pRORowset1->m_pIDBInitialize, IID_IDBProperties, DATASOURCE_INTERFACE,
|
|
(IUnknown **)&pIDBProp))
|
|
{
|
|
if (CHECK(pIDBProp->GetProperties(1, &PropIDSet, &cPropSets,
|
|
&rgPropSets), S_OK))
|
|
{
|
|
//We assume there is only one set with one property
|
|
COMPARE(cPropSets, 1);
|
|
COMPARE(rgPropSets[0].cProperties, 1);
|
|
if (V_BOOL(&(rgPropSets[0].rgProperties[0].vValue)) == VARIANT_TRUE)
|
|
m_fPassByRef = TRUE;
|
|
else
|
|
{
|
|
m_fPassByRef = FALSE;
|
|
}
|
|
}
|
|
|
|
if(rgPropSets)
|
|
{
|
|
if(rgPropSets->rgProperties)
|
|
{
|
|
PROVIDER_FREE(rgPropSets->rgProperties);
|
|
}
|
|
|
|
PROVIDER_FREE(rgPropSets);
|
|
}
|
|
if (pIDBProp)
|
|
{
|
|
pIDBProp->Release();
|
|
pIDBProp = NULL;
|
|
}
|
|
}
|
|
|
|
//Find out if STRONGIDENTITY is supported
|
|
if (VerifyInterface(m_pRORowset1->m_pIAccessor, IID_IRowsetInfo, ROWSET_INTERFACE,
|
|
(IUnknown **)&pIRowInfo))
|
|
{
|
|
PropID = DBPROP_STRONGIDENTITY;
|
|
PropIDSet.guidPropertySet = DBPROPSET_ROWSET;
|
|
PropIDSet.cPropertyIDs = 1;
|
|
PropIDSet.rgPropertyIDs = &PropID;
|
|
|
|
if (CHECK(pIRowInfo->GetProperties(1, &PropIDSet, &cPropSets,
|
|
&rgPropSets), S_OK))
|
|
{
|
|
//We assume there is only one set with one property
|
|
COMPARE(cPropSets, 1);
|
|
COMPARE(rgPropSets[0].cProperties, 1);
|
|
if (V_BOOL(&(rgPropSets[0].rgProperties[0].vValue)) == VARIANT_TRUE)
|
|
m_fStrongIdentity = TRUE;
|
|
else
|
|
{
|
|
m_fStrongIdentity = FALSE;
|
|
}
|
|
}
|
|
|
|
if(rgPropSets)
|
|
{
|
|
if(rgPropSets->rgProperties)
|
|
{
|
|
PROVIDER_FREE(rgPropSets->rgProperties);
|
|
}
|
|
|
|
PROVIDER_FREE(rgPropSets);
|
|
}
|
|
if (pIRowInfo)
|
|
{
|
|
pIRowInfo->Release();
|
|
pIRowInfo = NULL;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
//--------------------------------------------------------------------
|
|
// @mfunc Checks if properties' status are correct for mandatory props
|
|
//
|
|
// @rdesc TRUE or FALSE
|
|
//
|
|
BOOL CResynchRefresh::DidPropsFail(CTxnRowset * pRowset)
|
|
{
|
|
ULONG i, j;
|
|
//Look thru every property set
|
|
for (i=0; i<pRowset->m_cPropSets; i++)
|
|
{
|
|
//And every array of properties in each set
|
|
for (j=0; j< pRowset->m_rgPropSets[i].cProperties; j++)
|
|
{
|
|
//Fail immediately if any required properties aren't set OK,
|
|
if (pRowset->m_rgPropSets[i].rgProperties[j].dwOptions == DBPROPOPTIONS_REQUIRED &&
|
|
pRowset->m_rgPropSets[i].rgProperties[j].dwStatus != DBPROPSTATUS_OK)
|
|
{
|
|
odtLog<<L"Not all requested properties are supported.\n";
|
|
return TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
//All required properties were set OK
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
//--------------------------------------------------------------------
|
|
// @mfunc TestResynchRefresh
|
|
//
|
|
// @rdesc TRUE or FALSE
|
|
//
|
|
int CResynchRefresh::TestResynchRefresh(ETESTROWSETTYPE eTestRowsetType)
|
|
{
|
|
DBCOUNTITEM cRowsObtained = 0;
|
|
HROW hRow = DB_NULL_HROW;
|
|
HROW *phRow = &hRow;
|
|
BOOL fResults = FALSE;
|
|
BOOL fOverWrite = TRUE;
|
|
|
|
if (m_eTI==TI_IRowsetRefreshFALSE)
|
|
{
|
|
fOverWrite=FALSE;
|
|
}
|
|
|
|
//USE READONLY ROWSET
|
|
if (eTestRowsetType == EREADONLY)
|
|
{
|
|
//Get an hRow
|
|
if (CHECK(m_hr = m_pROIRowset->GetNextRows(NULL, 0, 1, &cRowsObtained, &phRow), S_OK))
|
|
{
|
|
if (CHECK(ResynchRefresh(DB_NULL_HCHAPTER, 1, phRow, fOverWrite, &m_cRowsResynched, &m_rghRowsResynched, &m_rgRowStatus,TRUE), S_OK))
|
|
{
|
|
CompareOutParams(1, phRow);
|
|
FreeOutParams();
|
|
|
|
if (CHECK(m_pROIRowset->GetData(hRow, m_hROAccessor, m_pResynchRowsetData), S_OK))
|
|
{
|
|
//Call our methods on it for read only rowset
|
|
if (CHECK(GetLastVisibleData(*phRow, m_hROAccessor, m_pResynchVisibleData,TRUE), S_OK))
|
|
{
|
|
//this was changed because the test tried to keep track of what
|
|
//values were in the first row of the rowset. provider can insert and delete
|
|
//anywhere they want in their cache so it was impossible to know
|
|
//for every provider. the only way to know what value is there is to
|
|
//read it in, which is the cache buffer
|
|
fResults = COMPARE(CompareBuffer(m_pResynchRowsetData,m_pResynchVisibleData,m_cBindings,m_rgBindings,m_pIMalloc,FALSE,FALSE,COMPARE_ONLY),TRUE);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (hRow != DB_NULL_HROW)
|
|
{
|
|
m_pROIRowset->ReleaseRows(1, &hRow, NULL, NULL, NULL);
|
|
}
|
|
}
|
|
else
|
|
//USE CHANGEABLE ROWSET
|
|
{
|
|
//Get an hRow
|
|
if (CHECK(m_hr = m_pChgIRowset->GetNextRows(NULL, 0, 1, &cRowsObtained, &phRow), S_OK))
|
|
{
|
|
if (CHECK(ResynchRefresh(DB_NULL_HCHAPTER, 1, phRow, fOverWrite, &m_cRowsResynched, &m_rghRowsResynched, &m_rgRowStatus,FALSE), S_OK))
|
|
{
|
|
CompareOutParams(1, phRow);
|
|
FreeOutParams();
|
|
|
|
if (CHECK(m_pChgIRowset->GetData(hRow, m_hChgAccessor, m_pResynchRowsetData), S_OK))
|
|
{
|
|
//Call our methods on it for changeable rowset
|
|
if (CHECK(GetLastVisibleData(*phRow, m_hChgAccessor, m_pResynchVisibleData,FALSE), S_OK))
|
|
{
|
|
//this was changed because the test tried to keep track of what
|
|
//values were in the first row of the rowset. provider can insert and delete
|
|
//anywhere they want in their cache so it was impossible to know
|
|
//for every provider. the only way to know what value is there is to
|
|
//read it in, which is the cache buffer
|
|
fResults = COMPARE(CompareBuffer(m_pResynchRowsetData,m_pResynchVisibleData,m_cBindings,m_rgBindings,m_pIMalloc,FALSE,FALSE,COMPARE_ONLY),TRUE);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (hRow != DB_NULL_HROW)
|
|
{
|
|
m_pChgIRowset->ReleaseRows(1, &hRow, NULL, NULL, NULL);
|
|
}
|
|
}
|
|
if (fResults)
|
|
return TEST_PASS;
|
|
else
|
|
return TEST_FAIL;
|
|
}
|
|
|
|
|
|
//--------------------------------------------------------------------
|
|
// @mfunc CreateResynchObjects
|
|
//
|
|
// @rdesc TRUE or FALSE
|
|
//
|
|
BOOL CResynchRefresh::CreateResynchObjects(ETESTINTERFACE eTI)
|
|
{
|
|
IRowsetIdentity *pIRowsetIdentity = NULL;
|
|
IRowsetLocate *pIRowsetLocate = NULL;
|
|
|
|
|
|
//Create all objects which deal with rowsets -- anything we
|
|
//will need to recreate if we release the rowset
|
|
m_hr = m_pChgRowset1->MakeRowset();
|
|
if (m_hr != S_OK)
|
|
{
|
|
//We want to fail the function if some of the properties aren't
|
|
//supported, but not increment the error count, as this just
|
|
//indicates optional interfaces weren't supported.
|
|
if (m_hr != DB_S_ERRORSOCCURRED)
|
|
{
|
|
//If it's not DB_S_ERRORSOCCURED, it could be DB_E_ERRORSOCCURRED
|
|
//for drivers which don't support any of the properties
|
|
CHECK(m_hr, DB_E_ERRORSOCCURRED);
|
|
|
|
goto FAILROWSET;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//If properties failed on SetProperty before execute, our return
|
|
//code won't reflect it, so check array ourselves for any required failures
|
|
if (DidPropsFail(m_pChgRowset1))
|
|
goto FAILROWSET;
|
|
}
|
|
|
|
|
|
m_hr = m_pRORowset1->MakeRowset();
|
|
if (m_hr != S_OK)
|
|
{
|
|
//We want to fail the function if some of the properties aren't
|
|
//supported, but not increment the error count, as this just
|
|
//indicates optional interfaces weren't supported.
|
|
if (m_hr != DB_S_ERRORSOCCURRED)
|
|
{
|
|
//If it's not DB_S_ERRORSOCCURED, it could be DB_E_ERRORSOCCURRED
|
|
//for drivers which don't support any of the properties
|
|
CHECK(m_hr, DB_E_ERRORSOCCURRED);
|
|
|
|
goto FAILROWSET;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//If properties failed on SetProperty before execute, our return
|
|
//code won't reflect it, so check array ourselves for any required failures
|
|
if (DidPropsFail(m_pRORowset1))
|
|
goto FAILROWSET;
|
|
}
|
|
|
|
m_hr = m_pChgRowset2->MakeRowset();
|
|
if (m_hr != S_OK)
|
|
{
|
|
//We want to fail the function if some of the properties aren't
|
|
//supported, but not increment the error count, as this just
|
|
//indicates optional interfaces weren't supported.
|
|
if (m_hr != DB_S_ERRORSOCCURRED)
|
|
{
|
|
//If it's not DB_S_ERRORSOCCURED, it could be DB_E_ERRORSOCCURRED
|
|
//for drivers which don't support any of the properties
|
|
CHECK(m_hr, DB_E_ERRORSOCCURRED);
|
|
|
|
goto FAILROWSET;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//If properties failed on SetProperty before execute, our return
|
|
//code won't reflect it, so check array ourselves for any required failures
|
|
if (DidPropsFail(m_pChgRowset2))
|
|
goto FAILROWSET;
|
|
}
|
|
|
|
if (eTI==TI_IRowsetResynch)
|
|
{
|
|
//IRowsetResynch is optional, fail here if it's not supported
|
|
if (!VerifyInterface(m_pChgRowset1->m_pIAccessor, IID_IRowsetResynch, ROWSET_INTERFACE, (IUnknown **)&m_pChgIRowsetResynch))
|
|
{
|
|
goto FAILROWSET;
|
|
}
|
|
if (!VerifyInterface(m_pRORowset1->m_pIAccessor, IID_IRowsetResynch, ROWSET_INTERFACE, (IUnknown **)&m_pROIRowsetResynch))
|
|
{
|
|
goto FAILROWSET;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//IRowsetResynch is optional, fail here if it's not supported
|
|
if (!VerifyInterface(m_pChgRowset1->m_pIAccessor, IID_IRowsetRefresh, ROWSET_INTERFACE, (IUnknown **)&m_pChgIRowsetRefresh))
|
|
{
|
|
goto FAILROWSET;
|
|
}
|
|
if (!VerifyInterface(m_pRORowset1->m_pIAccessor, IID_IRowsetRefresh, ROWSET_INTERFACE, (IUnknown **)&m_pROIRowsetRefresh))
|
|
{
|
|
goto FAILROWSET;
|
|
}
|
|
}
|
|
|
|
//Get IRowset ptr used for freeing hRows
|
|
if (VerifyInterface(m_pChgRowset1->m_pIAccessor, IID_IRowset, ROWSET_INTERFACE, (IUnknown **)&m_pChgIRowset))
|
|
{
|
|
if (VerifyInterface(m_pRORowset1->m_pIAccessor, IID_IRowset, ROWSET_INTERFACE, (IUnknown **)&m_pROIRowset))
|
|
{
|
|
if (m_fRequestLongDataIfSupported &&
|
|
VerifyInterface(m_pChgRowset1->m_pIAccessor, IID_IRowsetLocate,
|
|
ROWSET_INTERFACE, (IUnknown **)&pIRowsetLocate))
|
|
{
|
|
//We only want to bind long data if we know the
|
|
//table's long data columns will be updated by
|
|
//all rowsets manipulating them
|
|
m_pChgRowset1->m_fBindLongData = BLOB_LONG;
|
|
m_pChgRowset2->m_fBindLongData = BLOB_LONG;
|
|
|
|
m_fBindLongData = BLOB_LONG;
|
|
|
|
if (pIRowsetLocate)
|
|
{
|
|
pIRowsetLocate->Release();
|
|
pIRowsetLocate = NULL;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
m_fBindLongData = NO_BLOB_COLS;
|
|
}
|
|
|
|
//Create accessor for changeable rowset and keep the bindings
|
|
if (CHECK(GetAccessorAndBindings( m_pChgRowset1->m_pIAccessor, DBACCESSOR_ROWDATA,
|
|
&m_hChgAccessor, &m_rgBindings, &m_cBindings, &m_cbRowSize,
|
|
DBPART_VALUE | DBPART_LENGTH | DBPART_STATUS,
|
|
UPDATEABLE_COLS_BOUND,FORWARD, NO_COLS_BY_REF, NULL, NULL,
|
|
NULL, DBTYPE_EMPTY, 0, NULL, NULL,
|
|
NO_COLS_OWNED_BY_PROV, DBPARAMIO_NOTPARAM,
|
|
m_fBindLongData),S_OK))
|
|
{
|
|
//Now create an accesor for the Read Only rowset using the same bindings
|
|
if (CHECK(m_pRORowset1->m_pIAccessor->CreateAccessor(DBACCESSOR_ROWDATA,
|
|
m_cBindings, m_rgBindings, m_cbRowSize, &m_hROAccessor, NULL), S_OK))
|
|
//Note, this frees them first if they exist and reallocs the correct size
|
|
//to match the accessors we just created
|
|
{
|
|
if (AllocDataBuffers(m_cbRowSize))
|
|
{
|
|
g_ulRowSize=m_cbRowSize;
|
|
return TRUE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
FAILROWSET:
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
//--------------------------------------------------------------------
|
|
// @mfunc ReleaseResynchObjects
|
|
//
|
|
// @rdesc TRUE or FALSE
|
|
//
|
|
void CResynchRefresh::ReleaseResynchObjects()
|
|
{
|
|
//Create all objects which deal with rowsets -- anything we
|
|
//will need to recreate if we release the rowset
|
|
|
|
if (m_pChgRowset1)
|
|
{
|
|
if (m_hChgAccessor != DB_NULL_HACCESSOR)
|
|
{
|
|
m_pChgRowset1->m_pIAccessor->ReleaseAccessor(m_hChgAccessor, NULL);
|
|
m_hChgAccessor = DB_NULL_HACCESSOR;
|
|
}
|
|
//m_pChgRowset1->ReleaseRowsetObject();
|
|
//Release array generated in ExecuteCommand call
|
|
if( m_pChgRowset1->m_rgTableColOrds )
|
|
{
|
|
PROVIDER_FREE(m_pChgRowset1->m_rgTableColOrds);
|
|
m_pChgRowset1->m_rgTableColOrds = NULL;
|
|
}
|
|
|
|
if(m_pChgRowset1->m_pIAccessor)
|
|
{
|
|
m_pChgRowset1->m_pIAccessor->Release();
|
|
m_pChgRowset1->m_pIAccessor = NULL;
|
|
}
|
|
}
|
|
if (m_pRORowset1)
|
|
{
|
|
if (m_hROAccessor != DB_NULL_HACCESSOR)
|
|
{
|
|
m_pRORowset1->m_pIAccessor->ReleaseAccessor(m_hROAccessor, NULL);
|
|
m_hROAccessor = DB_NULL_HACCESSOR;
|
|
}
|
|
//m_pRORowset1->ReleaseRowsetObject();
|
|
if( m_pRORowset1->m_rgTableColOrds )
|
|
{
|
|
PROVIDER_FREE(m_pRORowset1->m_rgTableColOrds);
|
|
m_pRORowset1->m_rgTableColOrds = NULL;
|
|
}
|
|
|
|
if(m_pRORowset1->m_pIAccessor)
|
|
{
|
|
m_pRORowset1->m_pIAccessor->Release();
|
|
m_pRORowset1->m_pIAccessor = NULL;
|
|
}
|
|
}
|
|
|
|
if (m_pChgRowset2)
|
|
{
|
|
//m_pChgRowset2->ReleaseRowsetObject();
|
|
if( m_pChgRowset2->m_rgTableColOrds )
|
|
{
|
|
PROVIDER_FREE(m_pChgRowset2->m_rgTableColOrds);
|
|
m_pChgRowset2->m_rgTableColOrds = NULL;
|
|
}
|
|
|
|
if(m_pChgRowset2->m_pIAccessor)
|
|
{
|
|
m_pChgRowset2->m_pIAccessor->Release();
|
|
m_pChgRowset2->m_pIAccessor = NULL;
|
|
}
|
|
|
|
}
|
|
|
|
if (m_pChgIRowsetResynch)
|
|
{
|
|
m_pChgIRowsetResynch->Release();
|
|
m_pChgIRowsetResynch = NULL;
|
|
}
|
|
if (m_pROIRowsetResynch)
|
|
{
|
|
m_pROIRowsetResynch->Release();
|
|
m_pROIRowsetResynch = NULL;
|
|
}
|
|
|
|
if (m_pChgIRowsetRefresh)
|
|
{
|
|
m_pChgIRowsetRefresh->Release();
|
|
m_pChgIRowsetRefresh = NULL;
|
|
}
|
|
if (m_pROIRowsetRefresh)
|
|
{
|
|
m_pROIRowsetRefresh->Release();
|
|
m_pROIRowsetRefresh = NULL;
|
|
}
|
|
|
|
if (m_pChgIRowset)
|
|
{
|
|
m_pChgIRowset->Release();
|
|
m_pChgIRowset = NULL;
|
|
}
|
|
|
|
if (m_pROIRowset)
|
|
{
|
|
m_pROIRowset->Release();
|
|
m_pROIRowset = NULL;
|
|
}
|
|
FreeBuffers(g_ulRowSize);
|
|
FreeAccessorBindings(m_cBindings,m_rgBindings);
|
|
m_rgBindings = NULL;
|
|
m_cBindings = 0;
|
|
}
|
|
|
|
|
|
//--------------------------------------------------------------------
|
|
// @mfunc Sets all CTxnRowset properties, but moves OTHERINSERT
|
|
// back to the default if it is currently one of the set properties
|
|
// -- this will allow the provider to set OTHERINSERT if it
|
|
// is needed for the other requested properties to be met, but not require
|
|
// it to be either on or off.
|
|
// We need to move OTHERINSERT to default since we set it explicitly on in the
|
|
// CTxnChgRowset::Init code, but for IRowsetResynch on some providers
|
|
// this property could conflict with CANHOLDROWS. So we leave
|
|
// it up to the provider whether or not it is set, and then just set
|
|
// whatever other properties we need for the particular test we are doing.
|
|
//
|
|
// @rdesc TRUE or FALSE
|
|
//
|
|
BOOL CResynchRefresh::SetAllProperties(CTxnRowset *pTxnRowset,
|
|
ULONG cAdditionalProps,
|
|
DBPROP *rgAdditionalProps)
|
|
{
|
|
ULONG cNewProps = 0;
|
|
DBPROP *rgNewDBProp = NULL;
|
|
ULONG i = 0;
|
|
ULONG j = 0;
|
|
DBPROPSET NewPropSet;
|
|
ULONG cOldProps = 0;
|
|
BOOL fFoundOtherInsert = FALSE;
|
|
ULONG ulNextPropIdx = 0;
|
|
|
|
if (pTxnRowset->m_rgPropSets)
|
|
cOldProps = pTxnRowset->m_rgPropSets[0].cProperties;
|
|
|
|
//Find OTHERINSERT and make it the default value if it exists
|
|
for (i=0; i<cOldProps; i++)
|
|
{
|
|
if (pTxnRowset->m_rgPropSets[0].rgProperties[i].dwPropertyID == DBPROP_OTHERINSERT)
|
|
{
|
|
pTxnRowset->m_rgPropSets[0].rgProperties[i].dwOptions = 0;
|
|
pTxnRowset->m_rgPropSets[0].rgProperties[i].colid = DB_NULLID;
|
|
pTxnRowset->m_rgPropSets[0].rgProperties[i].vValue.vt = VT_EMPTY;
|
|
fFoundOtherInsert = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
//We want to make sure we don't have more than one property set
|
|
ASSERT(pTxnRowset->m_cPropSets < 2);
|
|
|
|
//Allocate memory for old props, plus the new ones
|
|
cNewProps = cOldProps + cAdditionalProps;
|
|
rgNewDBProp = (DBPROP *)PROVIDER_ALLOC((cNewProps+1) * sizeof(DBPROP));
|
|
if (!rgNewDBProp)
|
|
return FALSE;
|
|
|
|
//Copy our old properties over
|
|
if (cOldProps)
|
|
{
|
|
memcpy(rgNewDBProp, pTxnRowset->m_rgPropSets[0].rgProperties, (cOldProps * sizeof(DBPROP)));
|
|
}
|
|
|
|
ulNextPropIdx += cOldProps;
|
|
|
|
//Now copy in the new properties we want to set
|
|
for (i=ulNextPropIdx,j=cAdditionalProps; j>0; j--,i++)
|
|
{
|
|
//Copy to next slot in New array from next property in additional array
|
|
rgNewDBProp[i].dwPropertyID = rgAdditionalProps[j-1].dwPropertyID;
|
|
rgNewDBProp[i].dwOptions = rgAdditionalProps[j-1].dwOptions;
|
|
rgNewDBProp[i].colid = rgAdditionalProps[j-1].colid;
|
|
rgNewDBProp[i].vValue.vt = rgAdditionalProps[j-1].vValue.vt;
|
|
V_BOOL(&(rgNewDBProp[i].vValue)) = V_BOOL(&(rgAdditionalProps[j-1].vValue));
|
|
}
|
|
|
|
//Fill our single set struct of all new properties
|
|
NewPropSet.rgProperties = rgNewDBProp;
|
|
NewPropSet.cProperties = i;
|
|
NewPropSet.guidPropertySet = DBPROPSET_ROWSET;
|
|
|
|
//Now set properties including IRowsetResynch for our changeable rowset
|
|
pTxnRowset->SetRowsetProperties(&NewPropSet, 1);
|
|
|
|
//Cleanup
|
|
PROVIDER_FREE(rgNewDBProp);
|
|
rgNewDBProp = NULL;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
//--------------------------------------------------------------------
|
|
// @mfunc Does GetVisibleData and GetData on the cached row. Then
|
|
// does ResynchRows and GetData on the resynch'd row.
|
|
//
|
|
// @rdesc TRUE or FALSE
|
|
//
|
|
BOOL CResynchRefresh::GetDataBuffers (
|
|
CTxnRowset *pFirstTxnRowset,
|
|
ISOLEVEL fIsoLevel,
|
|
HACCESSOR hAccessor,
|
|
HROW hRow,
|
|
DBBINDING *rgBindings,
|
|
DBCOUNTITEM cBindings
|
|
)
|
|
{
|
|
BOOL fResults = FALSE;
|
|
IRowset *pIRowset = NULL;
|
|
IRowsetResynch *pIRowsetResynch = NULL;
|
|
IRowsetRefresh *pIRowsetRefresh = NULL;
|
|
ULONG cRowsObtained = 0;
|
|
IRowsetInfo *pIRowsetInfo = NULL;
|
|
DBPROPIDSET PropIDSet;
|
|
ULONG cPropSets = 0;
|
|
DBPROPSET *rgPropSets = NULL;
|
|
DBPROPSET rgRowsetPropSet;
|
|
DBPROPID rgRowPropIDs[1];
|
|
BOOL fImmobileRows = FALSE;
|
|
WORD i = 0;
|
|
HROW hFoundRow = DB_NULL_HROW;
|
|
HRESULT hr = S_OK;
|
|
DBBINDING *rgBindingsT = NULL;
|
|
DBCOUNTITEM cBindingsT = 0;
|
|
|
|
|
|
//if binding are NOT passed in used the class's default bindings
|
|
if (cBindings)
|
|
{
|
|
cBindingsT = cBindings;
|
|
rgBindingsT = rgBindings;
|
|
}
|
|
else
|
|
{
|
|
cBindingsT = m_cBindings;
|
|
rgBindingsT = m_rgBindings;
|
|
}
|
|
|
|
//Get IRowset on object
|
|
if (!VerifyInterface(pFirstTxnRowset->m_pIAccessor, IID_IRowset, ROWSET_INTERFACE,
|
|
(IUnknown **)&pIRowset))
|
|
goto CLEANUP;
|
|
|
|
//Get IRowsetInfo on object
|
|
if (!VerifyInterface(pFirstTxnRowset->m_pIAccessor, IID_IRowsetInfo, ROWSET_INTERFACE,
|
|
(IUnknown **)&pIRowsetInfo))
|
|
goto CLEANUP;
|
|
|
|
//check if rows will be moved when they are changed
|
|
//if this property is TRUE the rows should not be moved when IRowsetChange->SetData is called
|
|
rgRowPropIDs[0] = DBPROP_IMMOBILEROWS;
|
|
|
|
PropIDSet.cPropertyIDs = 1;
|
|
PropIDSet.rgPropertyIDs = rgRowPropIDs;
|
|
PropIDSet.guidPropertySet = DBPROPSET_ROWSET;
|
|
//Don't check return code as some or all of these may be unsupported
|
|
pIRowsetInfo->GetProperties(1, &PropIDSet, &cPropSets, &rgPropSets);
|
|
|
|
//Find the rowset property set
|
|
for (i=0; i<cPropSets; i++)
|
|
{
|
|
if (rgPropSets[i].guidPropertySet == DBPROPSET_ROWSET)
|
|
{
|
|
//Copy the set we want to check
|
|
memcpy(&rgRowsetPropSet, &rgPropSets[i], sizeof(DBPROPSET));
|
|
}
|
|
}
|
|
if (rgRowsetPropSet.rgProperties[0].dwStatus != DBPROPSTATUS_NOTSUPPORTED)
|
|
{
|
|
if (V_BOOL(&(rgRowsetPropSet.rgProperties[0].vValue)) == VARIANT_TRUE)
|
|
{
|
|
fImmobileRows = TRUE;
|
|
}
|
|
}
|
|
|
|
//Next GetData from rowset cache
|
|
hr=pIRowset->GetData(hRow, hAccessor, m_pRowsetData);
|
|
if (!hr==S_OK)
|
|
{
|
|
if (DB_S_ERRORSOCCURRED==hr)
|
|
{
|
|
DWORD cCount;
|
|
|
|
//loop through columns
|
|
for (cCount=0;cCount < cBindingsT;cCount++)
|
|
{
|
|
// switch (*((BYTE *)dwAddrGet+(rgBindingsT[cCount]).obStatus))
|
|
switch (STATUS_BINDING(rgBindingsT[cCount],m_pRowsetData))
|
|
{
|
|
case DBSTATUS_S_OK:
|
|
case DBSTATUS_S_ISNULL:
|
|
break;
|
|
case DBSTATUS_S_TRUNCATED:
|
|
case DBSTATUS_E_BADACCESSOR:
|
|
case DBSTATUS_E_CANTCONVERTVALUE:
|
|
case DBSTATUS_E_CANTCREATE:
|
|
case DBSTATUS_E_DATAOVERFLOW:
|
|
case DBSTATUS_E_SIGNMISMATCH:
|
|
case DBSTATUS_E_PERMISSIONDENIED:
|
|
case DBSTATUS_E_INTEGRITYVIOLATION:
|
|
case DBSTATUS_E_SCHEMAVIOLATION:
|
|
case DBSTATUS_E_BADSTATUS:
|
|
case DBSTATUS_S_DEFAULT:
|
|
//some error on some column :)
|
|
goto CLEANUP;
|
|
case DBSTATUS_E_UNAVAILABLE:
|
|
m_rghRowsResynched = NULL;
|
|
m_rgRowStatus = NULL;
|
|
fResults = TRUE;
|
|
g_fBlobFail = TRUE;
|
|
goto CLEANUP;
|
|
default:
|
|
//error, all possible status are above
|
|
goto CLEANUP;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
//GetVisibleData on our row if test is getting it from non refreshed visual cache
|
|
//if the interface is IRowsetRefresh and the provider implements a visual cache try GetLastVisibleData
|
|
//this visual cache should be the same as GetData
|
|
//(can't have a delete row here since there is a visual cache)
|
|
if (m_eTI!=TI_IRowsetResynch)
|
|
{
|
|
if (!VerifyInterface(pFirstTxnRowset->m_pIAccessor, IID_IRowsetRefresh, ROWSET_INTERFACE,
|
|
(IUnknown **)&pIRowsetRefresh))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
hr = pIRowsetRefresh->GetLastVisibleData(hRow, hAccessor, m_pVisibleData);
|
|
COMPARE(S_OK,hr);
|
|
}
|
|
else
|
|
{
|
|
if (!VerifyInterface(pFirstTxnRowset->m_pIAccessor, IID_IRowsetResynch, ROWSET_INTERFACE,
|
|
(IUnknown **)&pIRowsetResynch))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
hr = pIRowsetResynch->GetVisibleData(hRow, hAccessor, m_pVisibleData);
|
|
}
|
|
|
|
if (!hr==S_OK)
|
|
{
|
|
//account for the fact that some providers might delete/insert a row when asked to change it
|
|
//this may put a hole in the rowset and put the new row somewhere else in the rowset (most likley at the end of the rowset)
|
|
if (DB_E_DELETEDROW==hr)
|
|
{
|
|
g_fDeletedRow = TRUE;
|
|
}
|
|
else
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
}
|
|
|
|
//Now do a ResynchRows to see if new data is brought in
|
|
if (m_eTI==TI_IRowsetResynch)
|
|
{
|
|
hr=pIRowsetResynch->ResynchRows(1, &hRow, &m_cRowsResynched, &m_rghRowsResynched, &m_rgRowStatus);
|
|
}
|
|
else
|
|
{
|
|
if (m_eTI==TI_IRowsetRefreshTRUE)
|
|
{
|
|
hr=pIRowsetRefresh->RefreshVisibleData(DB_NULL_HCHAPTER,1, &hRow, TRUE, &m_cRowsResynched, &m_rghRowsResynched, &m_rgRowStatus);
|
|
}
|
|
else
|
|
{
|
|
hr=pIRowsetRefresh->RefreshVisibleData(DB_NULL_HCHAPTER,1, &hRow, FALSE, &m_cRowsResynched, &m_rghRowsResynched, &m_rgRowStatus);
|
|
}
|
|
}
|
|
|
|
if (!hr==S_OK)
|
|
{
|
|
//account for the fact that some providers might delete/insert a row when asked to change it
|
|
//this may put a hole in the rowset and put the newrow somewhere else in the rowset (most likley at the end of the rowset)
|
|
if (DB_E_ERRORSOCCURRED==hr)
|
|
{
|
|
g_fDeletedRow = TRUE;
|
|
}
|
|
else
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
}
|
|
|
|
FreeOutParams();
|
|
|
|
//Get Newly Resynch'd Data
|
|
hr=pIRowset->GetData(hRow, hAccessor, m_pResynchRowsetData);
|
|
if (!hr==S_OK)
|
|
{
|
|
if (DB_S_ERRORSOCCURRED==hr)
|
|
{
|
|
DWORD cCount;
|
|
|
|
//loop through columns
|
|
for (cCount=0;cCount < cBindingsT;cCount++)
|
|
{
|
|
// switch (*((BYTE *)dwAddrGet+(rgBindingsT[cCount]).obStatus))
|
|
switch (STATUS_BINDING(rgBindingsT[cCount],m_pResynchRowsetData))
|
|
{
|
|
case DBSTATUS_S_OK:
|
|
case DBSTATUS_S_ISNULL:
|
|
break;
|
|
case DBSTATUS_S_TRUNCATED:
|
|
case DBSTATUS_E_BADACCESSOR:
|
|
case DBSTATUS_E_CANTCONVERTVALUE:
|
|
case DBSTATUS_E_CANTCREATE:
|
|
case DBSTATUS_E_DATAOVERFLOW:
|
|
case DBSTATUS_E_SIGNMISMATCH:
|
|
case DBSTATUS_E_PERMISSIONDENIED:
|
|
case DBSTATUS_E_INTEGRITYVIOLATION:
|
|
case DBSTATUS_E_SCHEMAVIOLATION:
|
|
case DBSTATUS_E_BADSTATUS:
|
|
case DBSTATUS_S_DEFAULT:
|
|
//some error on some column :)
|
|
goto CLEANUP;
|
|
case DBSTATUS_E_UNAVAILABLE:
|
|
m_rghRowsResynched = NULL;
|
|
m_rgRowStatus = NULL;
|
|
fResults = TRUE;
|
|
g_fBlobFail = TRUE;
|
|
goto CLEANUP;
|
|
default:
|
|
//error, all possible status are above
|
|
goto CLEANUP;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//Now GetVisibleData on our row
|
|
//this now should come after the call to resynch the cache to make sure
|
|
//that the visible cache has the current data from the back end.
|
|
if (m_eTI==TI_IRowsetResynch)
|
|
{
|
|
hr=pIRowsetResynch->GetVisibleData(hRow, hAccessor, m_pResynchVisibleData);
|
|
}
|
|
else
|
|
{
|
|
hr=pIRowsetRefresh->GetLastVisibleData(hRow, hAccessor, m_pResynchVisibleData);
|
|
}
|
|
|
|
if (!hr==S_OK)
|
|
{
|
|
//account for the fact that some providers might delete/insert a row when asked to change it
|
|
//this may put a hole in the rowset and put the new row somewhere else in the rowset (most likley at the end of the rowset)
|
|
if (DB_E_DELETEDROW==hr)
|
|
{
|
|
g_fDeletedRow = TRUE;
|
|
}
|
|
else
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
}
|
|
|
|
fResults = TRUE;
|
|
CLEANUP:
|
|
if(pIRowset)
|
|
{
|
|
pIRowset->Release();
|
|
pIRowset = NULL;
|
|
}
|
|
if(pIRowsetResynch)
|
|
{
|
|
pIRowsetResynch->Release();
|
|
pIRowsetResynch = NULL;
|
|
}
|
|
if(pIRowsetRefresh)
|
|
{
|
|
pIRowsetRefresh->Release();
|
|
pIRowsetRefresh = NULL;
|
|
}
|
|
if(pIRowsetInfo)
|
|
{
|
|
pIRowsetInfo->Release();
|
|
pIRowsetInfo = NULL;
|
|
}
|
|
PROVIDER_FREE(rgPropSets[0].rgProperties);
|
|
PROVIDER_FREE(rgPropSets);
|
|
return fResults;
|
|
}
|
|
|
|
|
|
//--------------------------------------------------------------------
|
|
// @mfunc Makes the change on a second txn, then retrieves corresponding
|
|
// hRow for that row before the data has been resynch'd.
|
|
//
|
|
// @rdesc TRUE or FALSE
|
|
//
|
|
BOOL CResynchRefresh::ChangeUnderlyingRowAndGetHrow( CTxnRowset *pFirstTxnRowset,
|
|
ISOLEVEL fIsoLevel,
|
|
HROW *phRow)
|
|
{
|
|
HROW hKeepRow;
|
|
IRowset *pIRowset = NULL;
|
|
BOOL fResults = FALSE;
|
|
|
|
//Get IRowset on the object
|
|
if (!VerifyInterface(pFirstTxnRowset->m_pIAccessor, IID_IRowset, ROWSET_INTERFACE,
|
|
(IUnknown **)&pIRowset))
|
|
goto CLEANUP;
|
|
//Get row so that consumer has it in cache before we change it from another txn
|
|
if (!COMPARE(pFirstTxnRowset->FindRow(GetNextRowToDelete(), &hKeepRow), TRUE))
|
|
{
|
|
// PrintRowset((IRowset*)pIRowset);
|
|
odtLog << L"No "<<GetNextRowToDelete() << "\n";
|
|
goto CLEANUP;
|
|
}
|
|
//Only keep this hRow if caller wants it
|
|
if (phRow)
|
|
*phRow = hKeepRow;
|
|
else
|
|
pIRowset->ReleaseRows(1, &hKeepRow, NULL, NULL, NULL);
|
|
|
|
//Change row from another txn -- we always use m_pChgRowset2, regardless
|
|
//of which rowset (RO or Chg) from which we call GetVisibleData
|
|
fResults = Change(m_pChgRowset2);
|
|
|
|
//Change may not have succeeded due to txn locking, so we
|
|
//can only expect success if the isolation is low enough
|
|
//We pass CHAOS when there is no txn
|
|
if (fIsoLevel == ISOLATIONLEVEL_CHAOS ||
|
|
fIsoLevel == ISOLATIONLEVEL_READUNCOMMITTED ||
|
|
fIsoLevel == ISOLATIONLEVEL_READCOMMITTED)
|
|
{
|
|
COMPARE(fResults, TRUE);
|
|
|
|
//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
|
|
}
|
|
else
|
|
{
|
|
if (!fResults)
|
|
{
|
|
odtLog << L"Updating a row failed, possibly due to higher isolation levels locking the row on which the update failed.\n";
|
|
//g_DeleteIncrement();
|
|
m_fNoChange = TRUE;
|
|
fResults = TRUE;
|
|
}
|
|
}
|
|
CLEANUP:
|
|
if(pIRowset)
|
|
{
|
|
pIRowset->Release();
|
|
pIRowset = NULL;
|
|
}
|
|
return fResults;
|
|
}
|
|
|
|
//--------------------------------------------------------------------
|
|
// @mfunc Calls ChangeUnderlyingRowAndGetHrow and GetDataBuffers
|
|
// to generate the scenario we need to call VerifyData
|
|
//
|
|
// @rdesc TRUE or FALSE
|
|
//
|
|
BOOL CResynchRefresh::GenerateResynchData(
|
|
CTxnRowset *pFirstTxnRowset,
|
|
ISOLEVEL fIsoLevel,
|
|
HACCESSOR hAccessor,
|
|
DBBINDING *rgBindings,
|
|
DBCOUNTITEM cBindings
|
|
)
|
|
{
|
|
HROW hRow = DB_NULL_HROW;
|
|
HROW hRowChanged = DB_NULL_HROW;
|
|
IRowset *pIRowset = NULL;
|
|
BOOL fResults = FALSE;
|
|
|
|
if (VerifyInterface(pFirstTxnRowset->m_pIAccessor, IID_IRowset, ROWSET_INTERFACE,
|
|
(IUnknown **)&pIRowset))
|
|
{
|
|
//Make a change via another txn and get the corresponding hRow on first txn
|
|
if (ChangeUnderlyingRowAndGetHrow(pFirstTxnRowset, fIsoLevel, &hRow) != NOERROR)
|
|
{
|
|
//Fill all data buffers using Resynch methods
|
|
if (GetDataBuffers(pFirstTxnRowset, fIsoLevel, hAccessor, hRow, rgBindings, cBindings))
|
|
{
|
|
fResults = TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
//Release hRow
|
|
if (pIRowset)
|
|
{
|
|
if (hRow != DB_NULL_HROW)
|
|
CHECK(pIRowset->ReleaseRows(1, &hRow, NULL, NULL, NULL), S_OK);
|
|
pIRowset->Release();
|
|
pIRowset = NULL;
|
|
}
|
|
|
|
return fResults;
|
|
}
|
|
|
|
|
|
//--------------------------------------------------------------------
|
|
// @mfunc Verifies the correct contents of the visible and cached data
|
|
// buffers, based on the fSeeNewVisibleData flag.
|
|
//
|
|
// @rdesc TRUE or FALSE
|
|
//
|
|
BOOL CResynchRefresh::VerifyData( EVERIFY fSeeVisibleResynchedData,
|
|
EVERIFY fSeeVisibleData,
|
|
EVERIFY fSeeRowsetData, //= VERIFY_OLD
|
|
EVERIFY fSeeRowsetResynchedData, //= VERIFY_NEW
|
|
ULONG ulOldRowNum, //= 0
|
|
ULONG ulNewRowNum, //= 0
|
|
DBCOUNTITEM cVerifyBindings, //= 0
|
|
DBBINDING *rgVerifyBindings) //= NULL
|
|
{
|
|
BOOL fResults = FALSE;
|
|
DBCOUNTITEM cBindings = cVerifyBindings;
|
|
DBBINDING *rgBindings = rgVerifyBindings;
|
|
|
|
if (g_fDeletedRow || g_fBlobFail)
|
|
{
|
|
//if this is true then the provider inserted/deleted a row instead of changing it
|
|
//if this is done the first rowset has no knoweldge of the new row, it can't see it nor get it
|
|
//so it can't compare against either
|
|
//or
|
|
//a BLOB column was in a row that was inserted and some providers have a hard time handling
|
|
//BLOBs so they don't
|
|
g_fDeletedRow = FALSE;
|
|
g_fBlobFail = FALSE;
|
|
return TRUE;
|
|
}
|
|
|
|
//If we haven't been passed any bindings, use the defaults
|
|
if (!cBindings)
|
|
{
|
|
cBindings = m_cBindings;
|
|
rgBindings = m_rgBindings;
|
|
}
|
|
|
|
//If ulOldRowNum is zero, we use the currently changed row num
|
|
if (!ulOldRowNum)
|
|
{
|
|
ulOldRowNum = g_ulLastActualDelete;
|
|
}
|
|
//if the second Txn did not change anything
|
|
if (m_fNoChange)
|
|
{
|
|
ulOldRowNum = GetNextRowToDelete();
|
|
m_fNoChange = FALSE;
|
|
}
|
|
//Same for ulNewRowNum
|
|
if (!ulNewRowNum)
|
|
{
|
|
ulNewRowNum = g_ulLastActualInsert;
|
|
}
|
|
|
|
//fSeeRowsetResynchedData - GetData after call to Resynch
|
|
if (fSeeRowsetResynchedData == VERIFY_NEW)
|
|
{
|
|
if (m_eTI==TI_IRowsetRefreshFALSE)
|
|
{
|
|
//resynch'd data should always be the old values for RefreshFALSE, even
|
|
//if fSeeRowsetResynchedData says to expect new values
|
|
//there is no visual cache this will still be the old vaules since the resynch calls
|
|
//should have been a no-op
|
|
if (!COMPARE(CompareData(m_pChgRowset1->m_pTable->CountColumnsOnTable(),
|
|
m_pChgRowset1->m_rgTableColOrds, ulOldRowNum, m_pResynchRowsetData,
|
|
cBindings, rgBindings, m_pChgRowset1->m_pTable,
|
|
m_pIMalloc, PRIMARY, COMPARE_ONLY), TRUE))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//resynch'd data should always be the new values for Resynch and RefreshTRUE
|
|
if (!COMPARE(CompareData(m_pChgRowset1->m_pTable->CountColumnsOnTable(),
|
|
m_pChgRowset1->m_rgTableColOrds, ulNewRowNum, m_pResynchRowsetData,
|
|
cBindings, rgBindings, m_pChgRowset1->m_pTable,
|
|
m_pIMalloc, PRIMARY, COMPARE_ONLY), TRUE))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (fSeeRowsetResynchedData == VERIFY_OLD)
|
|
{
|
|
//Unless we haven't changed anything in the second txn
|
|
if (!(CompareData(m_pChgRowset1->m_pTable->CountColumnsOnTable(),
|
|
m_pChgRowset1->m_rgTableColOrds, ulOldRowNum, m_pResynchRowsetData,
|
|
cBindings, rgBindings, m_pChgRowset1->m_pTable,
|
|
m_pIMalloc, PRIMARY, COMPARE_ONLY), TRUE))
|
|
goto CLEANUP;
|
|
}
|
|
}
|
|
|
|
//fSeeRowsetData - GetData before any resynch calls
|
|
if (fSeeRowsetData == VERIFY_NEW)
|
|
{
|
|
//If the hRow is a newly inserted row we'll see new values,
|
|
fResults = COMPARE(CompareData(m_pChgRowset1->m_pTable->CountColumnsOnTable(),
|
|
m_pChgRowset1->m_rgTableColOrds, ulNewRowNum, m_pRowsetData,
|
|
cBindings, rgBindings, m_pChgRowset1->m_pTable,
|
|
m_pIMalloc, PRIMARY, COMPARE_ONLY), TRUE);
|
|
}
|
|
else
|
|
{
|
|
if (fSeeRowsetData == VERIFY_OLD)
|
|
{
|
|
//otherwise the cache should always be old values that haven't been updated yet
|
|
if(!CompareData(m_pChgRowset1->m_pTable->CountColumnsOnTable(),
|
|
m_pChgRowset1->m_rgTableColOrds, ulOldRowNum, m_pRowsetData,
|
|
cBindings, rgBindings, m_pChgRowset1->m_pTable,
|
|
m_pIMalloc, PRIMARY, COMPARE_ONLY))
|
|
odtLog<<"Data mismatched due to wrong comparison in miscfunc\n";
|
|
fResults = TRUE;
|
|
|
|
}
|
|
}
|
|
|
|
//fSeeVisibleData - GetVisibleData before any resynch calls
|
|
if (m_eTI==TI_IRowsetResynch || !g_fVisualCache)
|
|
{
|
|
//this will always go to the back end since it was 'resynch' and not 'refresh'
|
|
//or because there is not a visual cache so the back end then becomes the only
|
|
//place GetVisibleData can get its data
|
|
if (fSeeVisibleData == VERIFY_NEW)
|
|
{
|
|
//Our visible data after resynch should be the new values if the second txn has changed the row
|
|
//fOverwrtie shouldn't matter with this buffer. this one gets overwritten reguardless.
|
|
fResults = COMPARE(CompareData(m_pChgRowset1->m_pTable->CountColumnsOnTable(),
|
|
m_pChgRowset1->m_rgTableColOrds, ulNewRowNum,
|
|
m_pVisibleData, cBindings, rgBindings, m_pChgRowset1->m_pTable,
|
|
m_pIMalloc, PRIMARY, COMPARE_ONLY), TRUE);
|
|
}
|
|
else
|
|
{
|
|
if (fSeeVisibleData == VERIFY_OLD)
|
|
{
|
|
//but if the txn hasn't changed anything, we'll see ole values here
|
|
if(!CompareData(m_pChgRowset1->m_pTable->CountColumnsOnTable(),
|
|
m_pChgRowset1->m_rgTableColOrds, ulOldRowNum,
|
|
m_pVisibleData, cBindings, rgBindings, m_pChgRowset1->m_pTable,
|
|
m_pIMalloc, PRIMARY, COMPARE_ONLY))
|
|
odtLog<<"Data mismatched due to wrong comparison in miscfunc\n";
|
|
fResults = TRUE;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (fSeeVisibleData != VERIFY_IGNORE)
|
|
{
|
|
//this is 'refresh' from a visual cache pre calls to resynch (just like GetData)
|
|
if (!CompareData(m_pChgRowset1->m_pTable->CountColumnsOnTable(),
|
|
m_pChgRowset1->m_rgTableColOrds, ulOldRowNum, m_pVisibleData,
|
|
cBindings, rgBindings, m_pChgRowset1->m_pTable,
|
|
m_pIMalloc, PRIMARY, COMPARE_ONLY))
|
|
odtLog<<"Data mismatched due to wrong comparison in miscfunc\n";
|
|
fResults = TRUE;
|
|
}
|
|
}
|
|
|
|
//fSeeVisibleResynchedData - GetVisibleData after resynch calls
|
|
//this should be the same no matter if there is a visual cache
|
|
if (fSeeVisibleResynchedData == VERIFY_NEW)
|
|
{
|
|
//Our visible data after resynch should be the new values if the second txn has changed the row
|
|
//fOverwrtie shouldn't matter with this buffer. this one gets overwritten reguardless.
|
|
fResults = COMPARE(CompareData(m_pChgRowset1->m_pTable->CountColumnsOnTable(),
|
|
m_pChgRowset1->m_rgTableColOrds, ulNewRowNum,
|
|
m_pResynchVisibleData, cBindings, rgBindings, m_pChgRowset1->m_pTable,
|
|
m_pIMalloc, PRIMARY, COMPARE_ONLY), TRUE);
|
|
}
|
|
else
|
|
{
|
|
if (fSeeVisibleResynchedData == VERIFY_OLD)
|
|
{
|
|
//but if the txn hasn't changed anything, we'll see ole values here
|
|
if (!CompareData(m_pChgRowset1->m_pTable->CountColumnsOnTable(),
|
|
m_pChgRowset1->m_rgTableColOrds, ulOldRowNum,
|
|
m_pResynchVisibleData, cBindings, rgBindings, m_pChgRowset1->m_pTable,
|
|
m_pIMalloc, PRIMARY, COMPARE_ONLY))
|
|
odtLog<<"Data mismatched due to wrong comparison in miscfunc\n";
|
|
fResults = TRUE;
|
|
}
|
|
}
|
|
|
|
//If we were supposed to ignore everything, return true
|
|
if (fSeeVisibleResynchedData == VERIFY_IGNORE &&
|
|
fSeeVisibleData == VERIFY_IGNORE &&
|
|
fSeeRowsetData == VERIFY_IGNORE &&
|
|
fSeeRowsetResynchedData == VERIFY_IGNORE)
|
|
{
|
|
fResults = TRUE;
|
|
}
|
|
CLEANUP:
|
|
return fResults;
|
|
}
|
|
|
|
//--------------------------------------------------------------------
|
|
// @mfunc Starts both Chg1 and RO1 rowsets in specificied transaction
|
|
// isolation level
|
|
//
|
|
// @rdesc TRUE or FALSE
|
|
//
|
|
HRESULT CResynchRefresh::StartTxns( ISOLEVEL fIsoLevel)
|
|
{
|
|
|
|
if (SUCCEEDED(m_hr = m_pChgRowset1->m_pITxnLocal->StartTransaction(fIsoLevel, 0, NULL, NULL)))
|
|
{
|
|
m_hr = m_pRORowset1->m_pITxnLocal->StartTransaction(fIsoLevel, 0, NULL, NULL);
|
|
}
|
|
|
|
return ResultFromScode(m_hr);
|
|
}
|
|
|
|
|
|
//--------------------------------------------------------------------
|
|
// @mfunc Ends both Chg1 and RO1 rowsets' transactions by doing a non
|
|
// retaining commit
|
|
//
|
|
// @rdesc TRUE or FALSE
|
|
//
|
|
BOOL CResynchRefresh::EndTxns(BOOL fAbort)
|
|
{
|
|
if (fAbort)
|
|
{
|
|
//End Transactions without starting new ones
|
|
m_pChgRowset1->m_pITxnLocal->Abort(NULL, FALSE, FALSE);
|
|
m_pRORowset1->m_pITxnLocal->Abort(NULL, FALSE, FALSE);
|
|
}
|
|
else
|
|
{
|
|
//End Transactions without starting new ones
|
|
m_pChgRowset1->m_pITxnLocal->Commit(FALSE, 0, 0);
|
|
m_pRORowset1->m_pITxnLocal->Commit(FALSE, 0, 0);
|
|
}
|
|
//Clean up rowsets in case they were zombied above
|
|
//do this before checking the isoloeves below because
|
|
//some providers might not allow starting a txn if a cursor is open
|
|
ReleaseResynchObjects();
|
|
|
|
//Make sure our isolation level is set for autocommit so we can do
|
|
//things like create updateable rowsets on SQL Server -- something
|
|
//prohibited if we are in Read Uncommitted. This is also here just
|
|
//to verify that we can set this property.
|
|
CHECK(m_pChgRowset1->SetAutoCommitIsoLevel(ISOLATIONLEVEL_READCOMMITTED), S_OK);
|
|
CHECK(m_pRORowset1->SetAutoCommitIsoLevel(ISOLATIONLEVEL_READCOMMITTED), S_OK);
|
|
|
|
//Generate new stuff for testcase again
|
|
return COMPARE(CreateResynchObjects(m_eTI), TRUE);
|
|
}
|
|
|
|
|
|
//--------------------------------------------------------------------
|
|
// @mfunc Turns off CANHOLDROWS, and adds the properties specified for
|
|
// m_pChgRowset1, m_pChgRowset2 and m_pRORowset1. Not that cRemoveProps must
|
|
// specify the number of elements in the rgRemoveProps and rgPropOptions
|
|
// arrays.
|
|
//
|
|
// @rdesc TRUE or FALSE
|
|
//
|
|
BOOL CResynchRefresh::ChangeProperties( ULONG cAddProps,
|
|
DBPROP *rgAddProps,
|
|
ULONG cRemoveProps,
|
|
DBPROPID *rgRemoveProps,
|
|
DBPROPOPTIONS *rgPropOptions,
|
|
BLOBTYPE fBindLongData)
|
|
{
|
|
ULONG i;
|
|
ULONG j;
|
|
|
|
//Make sure we only have one property set, we'll assume that from now on
|
|
ASSERT(m_pChgRowset1->m_cPropSets);
|
|
ASSERT(m_pChgRowset1->m_rgPropSets);
|
|
|
|
/////////////////////////////////////////////////////////////
|
|
//Now undo some of the stuff we don't want for this test case
|
|
//but that CResynchRefresh::Init does
|
|
/////////////////////////////////////////////////////////////
|
|
|
|
//Release accessors
|
|
ReleaseResynchObjects();
|
|
|
|
//Look in all properties of our first (and only)
|
|
//set for the ones we want to remove
|
|
for (i=0; i<m_pChgRowset1->m_rgPropSets[0].cProperties; i++)
|
|
{
|
|
//Look for each of the properties to be removed
|
|
for (j=0; j<cRemoveProps; j++)
|
|
{
|
|
if (m_pChgRowset1->m_rgPropSets[0].rgProperties[i].dwPropertyID == rgRemoveProps[j])
|
|
{
|
|
//Set Property to false to turn it off
|
|
V_BOOL(&(m_pChgRowset1->m_rgPropSets[0].rgProperties[i].vValue)) = VARIANT_FALSE;
|
|
//Set option as requested by caller for this property
|
|
m_pChgRowset1->m_rgPropSets[0].rgProperties[i].dwOptions = rgPropOptions[j];
|
|
}
|
|
}
|
|
}
|
|
|
|
//Look in all properties of our first (and only)
|
|
//set for the ones we want to remove
|
|
for (i=0; i<m_pChgRowset2->m_rgPropSets[0].cProperties; i++)
|
|
{
|
|
//Look for each of the properties to be removed
|
|
for (j=0; j<cRemoveProps; j++)
|
|
{
|
|
if (m_pChgRowset2->m_rgPropSets[0].rgProperties[i].dwPropertyID == rgRemoveProps[j])
|
|
{
|
|
//Set Property to false to turn it off
|
|
V_BOOL(&(m_pChgRowset2->m_rgPropSets[0].rgProperties[i].vValue)) = VARIANT_FALSE;
|
|
//Set option as requested by caller for this property
|
|
m_pChgRowset2->m_rgPropSets[0].rgProperties[i].dwOptions = rgPropOptions[j];
|
|
}
|
|
}
|
|
}
|
|
|
|
//and for read only rowset, too
|
|
for (i=0; i<m_pRORowset1->m_rgPropSets[0].cProperties; i++)
|
|
{
|
|
//Look for each of the properties to be removed
|
|
for (j=0; j<cRemoveProps; j++)
|
|
{
|
|
if (m_pRORowset1->m_rgPropSets[0].rgProperties[i].dwPropertyID == rgRemoveProps[j])
|
|
{
|
|
//Set Property to false to turn it off
|
|
V_BOOL(&(m_pRORowset1->m_rgPropSets[0].rgProperties[i].vValue)) = VARIANT_FALSE;
|
|
//Set option as requested by caller for this property
|
|
m_pRORowset1->m_rgPropSets[0].rgProperties[i].dwOptions = rgPropOptions[j];
|
|
}
|
|
}
|
|
}
|
|
|
|
//Set all original properties, plus those passed to us
|
|
if (SetAllProperties(m_pChgRowset1, cAddProps, rgAddProps))
|
|
{
|
|
if (SetAllProperties(m_pChgRowset2, cAddProps, rgAddProps))
|
|
{
|
|
if (SetAllProperties(m_pRORowset1, cAddProps, rgAddProps))
|
|
{
|
|
//set the flags for the objects so the accessors
|
|
//are created with the right columsn bound
|
|
m_pChgRowset1->m_fBindLongData = fBindLongData;
|
|
m_pChgRowset2->m_fBindLongData = fBindLongData;
|
|
|
|
|
|
//Now recreate the rowsets with the change in properties in effect
|
|
if (CreateResynchObjects(m_eTI))
|
|
return TRUE;
|
|
}
|
|
}
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
HRESULT CResynchRefresh::ResynchRefresh( HCHAPTER hChapter,
|
|
DBCOUNTITEM cRows,
|
|
const HROW rghRows[],
|
|
BOOL fOverwrite,
|
|
DBCOUNTITEM *pcRowsRefreshed,
|
|
HROW **prghRowsRefreshed,
|
|
DBROWSTATUS **prgRowStatus,
|
|
BOOL fRO)
|
|
{
|
|
if (TI_IRowsetResynch==m_eTI)
|
|
{
|
|
if (fRO)
|
|
{
|
|
return m_pROIRowsetResynch->ResynchRows( cRows,
|
|
rghRows,
|
|
pcRowsRefreshed,
|
|
prghRowsRefreshed,
|
|
prgRowStatus);
|
|
}
|
|
else
|
|
{
|
|
return m_pChgIRowsetResynch->ResynchRows( cRows,
|
|
rghRows,
|
|
pcRowsRefreshed,
|
|
prghRowsRefreshed,
|
|
prgRowStatus);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if(fRO)
|
|
{
|
|
return m_pROIRowsetRefresh->RefreshVisibleData( hChapter,
|
|
cRows,
|
|
rghRows,
|
|
fOverwrite,
|
|
pcRowsRefreshed,
|
|
prghRowsRefreshed,
|
|
prgRowStatus);
|
|
}
|
|
else
|
|
{
|
|
return m_pChgIRowsetRefresh->RefreshVisibleData( hChapter,
|
|
cRows,
|
|
rghRows,
|
|
fOverwrite,
|
|
pcRowsRefreshed,
|
|
prghRowsRefreshed,
|
|
prgRowStatus);
|
|
}
|
|
}
|
|
//should never get here
|
|
return E_FAIL;;
|
|
}
|
|
|
|
|
|
HRESULT CResynchRefresh::GetLastVisibleData( HROW hRow,
|
|
HACCESSOR hAccessor,
|
|
void *pData,
|
|
BOOL fRO)
|
|
{
|
|
if (TI_IRowsetResynch==m_eTI)
|
|
{
|
|
if (fRO)
|
|
{
|
|
return m_pROIRowsetResynch->GetVisibleData(hRow,hAccessor,pData);
|
|
}
|
|
else
|
|
{
|
|
return m_pChgIRowsetResynch->GetVisibleData(hRow,hAccessor,pData);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (fRO)
|
|
{
|
|
return m_pROIRowsetRefresh->GetLastVisibleData(hRow,hAccessor,pData);
|
|
}
|
|
else
|
|
{
|
|
return m_pChgIRowsetRefresh->GetLastVisibleData(hRow,hAccessor,pData);
|
|
}
|
|
}
|
|
//should never b=get here
|
|
return E_FAIL;
|
|
}
|
|
|
|
|
|
//--------------------------------------------------------------------
|
|
// @mfunc Terminate
|
|
//
|
|
// @rdesc TRUE or FALSE
|
|
//
|
|
BOOL CResynchRefresh::Terminate()
|
|
{
|
|
if (m_pVisibleData)
|
|
{
|
|
PROVIDER_FREE(m_pVisibleData);
|
|
m_pVisibleData = NULL;
|
|
}
|
|
|
|
if (m_pRowsetData)
|
|
{
|
|
PROVIDER_FREE(m_pRowsetData);
|
|
m_pRowsetData = NULL;
|
|
}
|
|
|
|
if (m_pResynchRowsetData)
|
|
{
|
|
PROVIDER_FREE(m_pResynchRowsetData);
|
|
m_pResynchRowsetData = NULL;
|
|
}
|
|
|
|
if (m_pResynchVisibleData)
|
|
{
|
|
PROVIDER_FREE(m_pResynchVisibleData);
|
|
m_pResynchVisibleData = NULL;
|
|
}
|
|
|
|
ReleaseResynchObjects();
|
|
|
|
//Release the bindings
|
|
if (m_rgBindings)
|
|
{
|
|
// PROVIDER_FREE(m_rgBindings);
|
|
// m_rgBindings = NULL;
|
|
}
|
|
|
|
return CTxnImmed::Terminate();
|
|
}
|
|
|
|
|
|
//////////////////////////////////////////////////////////////
|
|
//Base class for TCPropCanHoldRowsResynch and TCPropCanHoldRowsResynchBLOBS
|
|
//////////////////////////////////////////////////////////////
|
|
class CPropCanHoldRowsResynch : public CResynchRefresh
|
|
{
|
|
public:
|
|
//@cmember CTOR
|
|
CPropCanHoldRowsResynch(LPWSTR tcName) : CResynchRefresh(tcName){};
|
|
|
|
|
|
//@cmember Does the Fetch Position testing for different rowsets
|
|
int TestFetchPosition( IRowset *pIRowset,
|
|
IRowsetResynch *pIRowsetResynch,
|
|
IRowsetRefresh *pIRowsetRefesh);
|
|
|
|
//@cmember Tests Resynch/Refresh on first and last row for different rowsets
|
|
int TestRows1AndN( IRowset *pIRowset,
|
|
IRowsetResynch *pIRowsetResynch,
|
|
IRowsetRefresh *pIRowsetRefesh);
|
|
|
|
//@cmember Tests Resynch/Refresh on All Rows for different rowsets
|
|
int TestAllRows( IRowset *pIRowset,
|
|
IRowsetResynch *pIRowsetResynch,
|
|
IRowsetRefresh *pIRowsetRefesh);
|
|
};
|
|
|
|
//--------------------------------------------------------------------
|
|
// @mfunc Does the Fetch Position testing for different rowsets
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int CPropCanHoldRowsResynch::TestFetchPosition( IRowset *pIRowset,
|
|
IRowsetResynch *pIRowsetResynch,
|
|
IRowsetRefresh *pIRowsetRefresh)
|
|
{
|
|
const WORD wRow = 3;
|
|
HROW rghRow[wRow] = {DB_NULL_HROW, DB_NULL_HROW, DB_NULL_HROW};
|
|
HROW hRow2 = DB_NULL_HROW;
|
|
HROW *phRow = &rghRow[0];
|
|
HROW *phRow2 = &hRow2;
|
|
DBCOUNTITEM cRowsObtained = 0;
|
|
BOOL fResults = FALSE;
|
|
BYTE *pFirstRowData = NULL;
|
|
BYTE *pwRowthRowData = NULL;
|
|
DBBYTEOFFSET cbSkip = 0;
|
|
|
|
//Determine if we have a bookmark bound, in which case we need to
|
|
//skip the bookmark column when we memcmp our buffers, since
|
|
//the bookmark may change
|
|
if (IsRowsetPropSupported(pIRowset, DBPROP_BOOKMARKS) == DBPROPSTATUS_OK)
|
|
{
|
|
//Skip to next column bound -- this assumes status is the first
|
|
//element of the data struct
|
|
ASSERT(offsetof(DATA, sStatus) == 0);
|
|
cbSkip = m_rgBindings[1].obStatus;
|
|
}
|
|
|
|
pFirstRowData = (BYTE *)PROVIDER_ALLOC(m_cbRowSize);
|
|
if (!pFirstRowData)
|
|
{
|
|
odtLog << wszMemoryAllocationError;
|
|
return TEST_FAIL;
|
|
}
|
|
pwRowthRowData = (BYTE *)PROVIDER_ALLOC(m_cbRowSize);
|
|
if (!pwRowthRowData)
|
|
{
|
|
odtLog << wszMemoryAllocationError;
|
|
return TEST_FAIL;
|
|
}
|
|
|
|
memset(m_pRowsetData, 0, (size_t)m_cbRowSize);
|
|
memset(m_pResynchVisibleData, 0, (size_t)m_cbRowSize);
|
|
memset(pwRowthRowData, 0, (size_t)m_cbRowSize);
|
|
memset(pwRowthRowData, 0, (size_t)m_cbRowSize);
|
|
|
|
//Make sure we are at beginning of rowset after other variations
|
|
TESTC_(pIRowset->RestartPosition(NULL), S_OK);
|
|
|
|
//This will get us wRow rows
|
|
TESTC_(pIRowset->GetNextRows(NULL, 0, wRow, &cRowsObtained, &phRow), S_OK);
|
|
|
|
//Now GetData on the 1st and the wRowth row so we know what it is
|
|
TESTC_(pIRowset->GetData(phRow[0], m_hChgAccessor, pFirstRowData), S_OK);
|
|
TESTC_(pIRowset->GetData(phRow[wRow-1], m_hChgAccessor, pwRowthRowData), S_OK);
|
|
|
|
//Now Release all the rows and start at the beginning again
|
|
TESTC_(pIRowset->ReleaseRows(wRow, rghRow, NULL, NULL, NULL), S_OK);
|
|
TESTC_(pIRowset->RestartPosition(NULL), S_OK);
|
|
|
|
//This will get us wRow - 1 rows
|
|
TESTC_(m_hr = pIRowset->GetNextRows(NULL, 0, (wRow-1), &cRowsObtained, &phRow), S_OK);
|
|
|
|
//Resynch the first row
|
|
if (m_eTI==TI_IRowsetResynch)
|
|
{
|
|
TESTC_(pIRowsetResynch->ResynchRows(1, &rghRow[0], &m_cRowsResynched,&m_rghRowsResynched, &m_rgRowStatus),S_OK);
|
|
}
|
|
else
|
|
{
|
|
if (m_eTI==TI_IRowsetRefreshTRUE)
|
|
{
|
|
TESTC_(pIRowsetRefresh->RefreshVisibleData(DB_NULL_HCHAPTER,1, &rghRow[0], TRUE, &m_cRowsResynched,&m_rghRowsResynched, &m_rgRowStatus),S_OK);
|
|
}
|
|
else
|
|
{
|
|
TESTC_(pIRowsetRefresh->RefreshVisibleData(DB_NULL_HCHAPTER,1, &rghRow[0], FALSE, &m_cRowsResynched,&m_rghRowsResynched, &m_rgRowStatus),S_OK);
|
|
}
|
|
}
|
|
|
|
//Get visible data on first row
|
|
if (m_eTI==TI_IRowsetResynch)
|
|
{
|
|
TESTC_(pIRowsetResynch->GetVisibleData(rghRow[0], m_hChgAccessor,m_pResynchVisibleData),S_OK);
|
|
}
|
|
else
|
|
{
|
|
TESTC_(pIRowsetRefresh->GetLastVisibleData(rghRow[0], m_hChgAccessor,m_pResynchVisibleData),S_OK);
|
|
}
|
|
|
|
CompareOutParams(1, &rghRow[0]);
|
|
|
|
if (g_fNOCHANGE)
|
|
{
|
|
//no change was made here, if the provider can handle it, expect it
|
|
COMPARE(m_rgRowStatus[0], DBROWSTATUS_S_NOCHANGE);
|
|
}
|
|
else
|
|
{
|
|
COMPARE(m_rgRowStatus[0], DBROWSTATUS_S_OK);
|
|
}
|
|
|
|
//no change is made, these should be the same
|
|
if(CompareBuffer(pFirstRowData,m_pResynchVisibleData,m_cBindings,m_rgBindings,m_pIMalloc,FALSE,FALSE,COMPARE_ONLY)!=TRUE)
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
|
|
//Move to next row to verify that all of this did not
|
|
//screw up the fetch position, we should get the third row here
|
|
TESTC_(m_hr = pIRowset->GetNextRows(NULL, 0, 1, &cRowsObtained, &phRow2), S_OK);
|
|
|
|
//Now GetData
|
|
TESTC_(pIRowset->GetData(hRow2, m_hChgAccessor, m_pRowsetData), S_OK);
|
|
{
|
|
if(CompareBuffer(m_pRowsetData,pwRowthRowData,m_cBindings,m_rgBindings,m_pIMalloc,FALSE,FALSE,COMPARE_ONLY)==TRUE)
|
|
{
|
|
fResults = TRUE;
|
|
}
|
|
}
|
|
CLEANUP:
|
|
FreeOutParams();
|
|
|
|
if (rghRow[0] != DB_NULL_HROW)
|
|
{
|
|
pIRowset->ReleaseRows((wRow-1), rghRow, NULL, NULL, NULL);
|
|
}
|
|
if (hRow2 != DB_NULL_HROW)
|
|
{
|
|
pIRowset->ReleaseRows(1, &hRow2, NULL, NULL, NULL);
|
|
}
|
|
PROVIDER_FREE(pFirstRowData);
|
|
PROVIDER_FREE(pwRowthRowData);
|
|
|
|
if (fResults)
|
|
{
|
|
return TEST_PASS;
|
|
}
|
|
else
|
|
{
|
|
return TEST_FAIL;
|
|
}
|
|
}
|
|
|
|
|
|
//--------------------------------------------------------------------
|
|
// @mfunc Tests Resynch on first and last row for different rowsets
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int CPropCanHoldRowsResynch::TestRows1AndN( IRowset *pIRowset,
|
|
IRowsetResynch *pIRowsetResynch,
|
|
IRowsetRefresh *pIRowsetRefresh)
|
|
{
|
|
const ULONG ulMaxRows = NUM_ROWS * 3;
|
|
DBCOUNTITEM cRowsObtained = 0;
|
|
DBCOUNTITEM cFirstRowObtained = 0;
|
|
BOOL fResults = FALSE;
|
|
HROW hFirstRow = DB_NULL_HROW;
|
|
HROW *phFirstRow = &hFirstRow;
|
|
HROW rghRows[ulMaxRows];
|
|
HROW *phRows = &rghRows[0];
|
|
BYTE *pResynchVisibleData2 = NULL;
|
|
BYTE *pRowsetData2 = NULL;
|
|
BYTE *pResynchRowsetData2 = NULL;
|
|
BYTE *p1stRowData = NULL;
|
|
BYTE *pNthRowData = NULL;
|
|
DBBYTEOFFSET cbSkip = 0;
|
|
ULONG *rgRefCounts = NULL;
|
|
ULONG cFirstRowRefCount = 1; //Set it to non zero so we know it is changed by ReleaseRows
|
|
ULONG i = 0;
|
|
|
|
//Determine if we have a bookmark bound, in which case we need to
|
|
//skip the bookmark column when we memcmp our buffers, since
|
|
//the bookmark may change
|
|
if (IsRowsetPropSupported(pIRowset, DBPROP_BOOKMARKS) == DBPROPSTATUS_OK)
|
|
{
|
|
//Skip to next column bound -- this assumes status is the first
|
|
//element of the data struct
|
|
ASSERT(offsetof(DATA, sStatus) == 0);
|
|
cbSkip = m_rgBindings[1].obStatus;
|
|
}
|
|
|
|
p1stRowData = (BYTE *)PROVIDER_ALLOC(m_cbRowSize);
|
|
if (!p1stRowData)
|
|
{
|
|
odtLog << wszMemoryAllocationError;
|
|
return TEST_FAIL;
|
|
}
|
|
pNthRowData = (BYTE *)PROVIDER_ALLOC(m_cbRowSize);
|
|
if (!pNthRowData)
|
|
{
|
|
odtLog << wszMemoryAllocationError;
|
|
return TEST_FAIL;
|
|
}
|
|
pResynchVisibleData2 = (BYTE *)PROVIDER_ALLOC(m_cbRowSize);
|
|
if (!pResynchVisibleData2)
|
|
return TEST_FAIL;
|
|
|
|
pRowsetData2 = (BYTE *)PROVIDER_ALLOC(m_cbRowSize);
|
|
if (!pRowsetData2)
|
|
return TEST_FAIL;
|
|
|
|
pResynchRowsetData2 = (BYTE *)PROVIDER_ALLOC(m_cbRowSize);
|
|
if (!pResynchRowsetData2)
|
|
return TEST_FAIL;
|
|
|
|
memset(m_pRowsetData, 0, (size_t)m_cbRowSize);
|
|
memset(m_pVisibleData, 0, (size_t)m_cbRowSize);
|
|
memset(m_pResynchRowsetData, 0, (size_t)m_cbRowSize);
|
|
|
|
memset(pRowsetData2, 0, (size_t)m_cbRowSize);
|
|
memset(pResynchVisibleData2, 0, (size_t)m_cbRowSize);
|
|
memset(pResynchRowsetData2, 0, (size_t)m_cbRowSize);
|
|
|
|
memset(p1stRowData, 0, (size_t)m_cbRowSize);
|
|
memset(pNthRowData, 0, (size_t)m_cbRowSize);
|
|
|
|
//Make sure we are at beginning of rowset after other variations
|
|
pIRowset->RestartPosition(NULL);
|
|
|
|
//Get all the rows
|
|
m_hr = pIRowset->GetNextRows(NULL, 0, ulMaxRows, &cRowsObtained, &phRows);
|
|
|
|
if(!SUCCEEDED(m_hr))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
|
|
//Now GetData on the first row so we know what it is
|
|
TESTC_(pIRowset->GetData(phRows[0], m_hChgAccessor, p1stRowData), S_OK);
|
|
|
|
//Now GetData on the last row so we know what it is
|
|
TESTC_(pIRowset->GetData(phRows[cRowsObtained-1], m_hChgAccessor, pNthRowData), S_OK);
|
|
|
|
//Now Release all the rows
|
|
TESTC_(pIRowset->ReleaseRows(cRowsObtained, rghRows, NULL, NULL, NULL), S_OK);
|
|
|
|
//Make sure we are at beginning of rowset again
|
|
TESTC_(pIRowset->RestartPosition(NULL), S_OK);
|
|
|
|
//Get first row, this one will induce the CANHOLDROWS and force a refetch
|
|
TESTC_(pIRowset->GetNextRows(NULL, 0, 1, &cFirstRowObtained, &phFirstRow), S_OK);
|
|
|
|
//Get all remaining possible rows (use NUM_ROWS * 3 so we're sure to get all of them)
|
|
TESTC_(pIRowset->GetNextRows(NULL, 0, ulMaxRows, &cRowsObtained, &phRows), DB_S_ENDOFROWSET);
|
|
|
|
/////////////////////////////////
|
|
//Now get all data on first row and last hRow
|
|
/////////////////////////////////
|
|
|
|
//Get rowset data
|
|
TESTC_(pIRowset->GetData(hFirstRow, m_hChgAccessor, m_pRowsetData), S_OK);
|
|
TESTC_(pIRowset->GetData(rghRows[cRowsObtained-1], m_hChgAccessor, pRowsetData2), S_OK);
|
|
|
|
//Try to get new visible data
|
|
if (m_eTI==TI_IRowsetResynch)
|
|
{
|
|
TESTC_(pIRowsetResynch->GetVisibleData(hFirstRow, m_hChgAccessor,m_pResynchVisibleData), S_OK);
|
|
TESTC_(pIRowsetResynch->GetVisibleData(rghRows[cRowsObtained-1], m_hChgAccessor,pResynchVisibleData2), S_OK);
|
|
|
|
//Resynch the rows, using count of rows of 0
|
|
TESTC_(pIRowsetResynch->ResynchRows(0, NULL,&m_cRowsResynched,&m_rghRowsResynched, &m_rgRowStatus), S_OK);
|
|
}
|
|
else
|
|
{
|
|
//Resynch the rows, using count of rows of 0
|
|
if (m_eTI==TI_IRowsetRefreshTRUE)
|
|
{
|
|
TESTC_(pIRowsetRefresh->RefreshVisibleData(DB_NULL_HCHAPTER,0, NULL,TRUE, &m_cRowsResynched,&m_rghRowsResynched, &m_rgRowStatus), S_OK);
|
|
}
|
|
else
|
|
{
|
|
TESTC_(pIRowsetRefresh->RefreshVisibleData(DB_NULL_HCHAPTER,0, NULL,FALSE, &m_cRowsResynched,&m_rghRowsResynched, &m_rgRowStatus), S_OK);
|
|
}
|
|
TESTC_(pIRowsetRefresh->GetLastVisibleData(hFirstRow, m_hChgAccessor,m_pResynchVisibleData), S_OK);
|
|
TESTC_(pIRowsetRefresh->GetLastVisibleData(rghRows[cRowsObtained-1], m_hChgAccessor,pResynchVisibleData2), S_OK);
|
|
}
|
|
|
|
//Check by hand instead of calling CompareOutParams() since our hRows
|
|
//are not in a contiguous array as expected by this routine
|
|
COMPARE(cRowsObtained+cFirstRowObtained, m_cRowsResynched);
|
|
|
|
//Check first row
|
|
COMPARE(m_rghRowsResynched[0], hFirstRow);
|
|
|
|
//Check second thru last rows. Since we start with 1 due to the first row
|
|
//being checked already at index 0 in m_rghRowsResynched, we can go through
|
|
//i=cRowsObtained
|
|
for (i=1; i<=cRowsObtained; i++)
|
|
{
|
|
COMPARE(rghRows[i-1], m_rghRowsResynched[i]);
|
|
}
|
|
|
|
//Release these rows, we have ref counts on them already
|
|
TESTC_(pIRowset->ReleaseRows(m_cRowsResynched, m_rghRowsResynched, NULL, NULL, NULL), S_OK);
|
|
|
|
while (m_cRowsResynched)
|
|
{
|
|
//Make our 1-based count a 0-based array index
|
|
m_cRowsResynched--;
|
|
|
|
if (g_fNOCHANGE)
|
|
{
|
|
//no change was made here, if the provider can handle it, expect it
|
|
COMPARE(m_rgRowStatus[m_cRowsResynched], DBROWSTATUS_S_NOCHANGE);
|
|
}
|
|
else
|
|
{
|
|
COMPARE(m_rgRowStatus[m_cRowsResynched], DBROWSTATUS_S_OK);
|
|
}
|
|
}
|
|
|
|
//Get resynch'd data
|
|
TESTC_(pIRowset->GetData(hFirstRow, m_hChgAccessor, m_pResynchRowsetData), S_OK);
|
|
TESTC_(pIRowset->GetData(rghRows[cRowsObtained-1], m_hChgAccessor, pResynchRowsetData2), S_OK);
|
|
|
|
//All data from our first row should still be old values
|
|
//since we didn't change anything underneath (fOvwewrite doesn't matter). We use
|
|
//cbSkip to adjust if we have bookmark data we need to ignore.
|
|
fResults = COMPARE(CompareBuffer(m_pResynchVisibleData,p1stRowData,m_cBindings,m_rgBindings,m_pIMalloc,FALSE,FALSE,COMPARE_ONLY),TRUE);
|
|
fResults &= COMPARE(CompareBuffer(m_pRowsetData,p1stRowData,m_cBindings,m_rgBindings,m_pIMalloc,FALSE,FALSE,COMPARE_ONLY),TRUE);
|
|
fResults &= COMPARE(CompareBuffer(m_pResynchRowsetData,p1stRowData,m_cBindings,m_rgBindings,m_pIMalloc,FALSE,FALSE,COMPARE_ONLY),TRUE);
|
|
|
|
//The same with data from our nth row
|
|
fResults &= COMPARE(CompareBuffer(pResynchVisibleData2,pNthRowData,m_cBindings,m_rgBindings,m_pIMalloc,FALSE,FALSE,COMPARE_ONLY),TRUE);
|
|
fResults &= COMPARE(CompareBuffer(pRowsetData2,pNthRowData,m_cBindings,m_rgBindings,m_pIMalloc,FALSE,FALSE,COMPARE_ONLY),TRUE);
|
|
fResults &= COMPARE(CompareBuffer(pResynchRowsetData2,pNthRowData,m_cBindings,m_rgBindings,m_pIMalloc,FALSE,FALSE,COMPARE_ONLY),TRUE);
|
|
|
|
|
|
rgRefCounts = (ULONG *)PROVIDER_ALLOC(cRowsObtained * sizeof(ULONG));
|
|
|
|
if (!rgRefCounts)
|
|
{
|
|
TESTC_(E_OUTOFMEMORY, S_OK); //Record that wblobse ran out of memory
|
|
}
|
|
else
|
|
{
|
|
//Verify the ref counts are correct for the second through last rows
|
|
TESTC_(pIRowset->ReleaseRows(cRowsObtained, rghRows, NULL, rgRefCounts, NULL), S_OK);
|
|
|
|
while (cRowsObtained)
|
|
{
|
|
cRowsObtained--; //Make the 1 based count a zero based index
|
|
|
|
COMPARE(rgRefCounts[cRowsObtained], 0);
|
|
}
|
|
}
|
|
|
|
//And make sure we release the first row and check the ref count
|
|
TESTC_(pIRowset->ReleaseRows(1, phFirstRow, NULL, &cFirstRowRefCount, NULL), S_OK);
|
|
|
|
COMPARE(cFirstRowRefCount, 0);
|
|
CLEANUP:
|
|
FreeOutParams();
|
|
|
|
if (rgRefCounts)
|
|
PROVIDER_FREE(rgRefCounts);
|
|
|
|
if (pResynchVisibleData2)
|
|
PROVIDER_FREE(pResynchVisibleData2);
|
|
|
|
if (pRowsetData2)
|
|
PROVIDER_FREE(pRowsetData2);
|
|
|
|
if (pResynchRowsetData2)
|
|
PROVIDER_FREE(pResynchRowsetData2);
|
|
|
|
if (p1stRowData)
|
|
PROVIDER_FREE(p1stRowData);
|
|
|
|
if (pNthRowData)
|
|
PROVIDER_FREE(pNthRowData);
|
|
|
|
if (fResults)
|
|
return TEST_PASS;
|
|
else
|
|
return TEST_FAIL;
|
|
}
|
|
|
|
|
|
//--------------------------------------------------------------------
|
|
// @mfunc Tests Resynch on All rows for different rowsets
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int CPropCanHoldRowsResynch::TestAllRows( IRowset *pIRowset,
|
|
IRowsetResynch *pIRowsetResynch,
|
|
IRowsetRefresh *pIRowsetRefresh)
|
|
{
|
|
const ULONG ulMaxRows = NUM_ROWS * 3;
|
|
HROW rghRows[ulMaxRows];
|
|
HROW *phRow = &rghRows[0];
|
|
DBCOUNTITEM cRowsObtained = 0;
|
|
BOOL fResults = FALSE;
|
|
ULONG i = 0;
|
|
DBCOUNTITEM ulArbitraryRowIdx = 0;
|
|
BYTE *pArbRowData = NULL;
|
|
DBBYTEOFFSET cbSkip = 0;
|
|
|
|
//Determine if we have a bookmark bound, in which case we need to
|
|
//skip the bookmark column when we memcmp our buffers, since
|
|
//the bookmark may changem
|
|
if (IsRowsetPropSupported(m_pChgIRowset, DBPROP_BOOKMARKS) == DBPROPSTATUS_OK)
|
|
{
|
|
//Skip to next column bound -- this assumes status is the first
|
|
//element of the data struct
|
|
ASSERT(offsetof(DATA, sStatus) == 0);
|
|
cbSkip = m_rgBindings[1].obStatus;
|
|
}
|
|
|
|
pArbRowData = (BYTE *)PROVIDER_ALLOC(m_cbRowSize);
|
|
if (!pArbRowData)
|
|
{
|
|
odtLog << wszMemoryAllocationError;
|
|
return TEST_FAIL;
|
|
}
|
|
|
|
memset(pArbRowData, 0, (size_t)m_cbRowSize);
|
|
memset(m_pRowsetData, 0, (size_t)m_cbRowSize);
|
|
memset(m_pVisibleData, 0, (size_t)m_cbRowSize);
|
|
memset(m_pResynchRowsetData, 0, (size_t)m_cbRowSize);
|
|
|
|
//Make sure we are at beginning of rowset after other variations
|
|
TESTC_(m_pChgIRowset->RestartPosition(NULL), S_OK);
|
|
|
|
//Now get all the rows, ask for more than enough
|
|
TESTC_(m_pChgIRowset->GetNextRows(NULL, 0, ulMaxRows, &cRowsObtained, &phRow), DB_S_ENDOFROWSET);
|
|
|
|
/////////////////////////////////////////////////////////////
|
|
//Fet all data on one arbitrary row
|
|
/////////////////////////////////////////////////////////////
|
|
ASSERT(cRowsObtained > 1);
|
|
ulArbitraryRowIdx = cRowsObtained - 2;
|
|
|
|
//Get data for verification use later
|
|
TESTC_(m_pChgIRowset->GetData(phRow[ulArbitraryRowIdx], m_hChgAccessor, pArbRowData), S_OK);
|
|
|
|
TESTC_(m_pChgIRowset->ReleaseRows(cRowsObtained, phRow, NULL, NULL, NULL), S_OK);
|
|
|
|
//Make sure we are at beginning of rowset
|
|
TESTC_(m_pChgIRowset->RestartPosition(NULL), S_OK);
|
|
|
|
//Now get all the rows, ask for more than enough
|
|
TESTC_(m_pChgIRowset->GetNextRows(NULL, 0, ulMaxRows, &cRowsObtained, &phRow), DB_S_ENDOFROWSET);
|
|
|
|
//Get cached data
|
|
TESTC_(m_pChgIRowset->GetData(phRow[ulArbitraryRowIdx], m_hChgAccessor, m_pRowsetData), S_OK);
|
|
|
|
//Try to get new visible data
|
|
if (m_eTI==TI_IRowsetResynch)
|
|
{
|
|
TESTC_(m_pChgIRowsetResynch->GetVisibleData(phRow[ulArbitraryRowIdx], m_hChgAccessor, m_pResynchVisibleData), S_OK);
|
|
|
|
//Resynch the rows
|
|
TESTC_(m_pChgIRowsetResynch->ResynchRows(cRowsObtained, phRow, &m_cRowsResynched,&m_rghRowsResynched, &m_rgRowStatus), S_OK);
|
|
}
|
|
else
|
|
{
|
|
//Resynch the rows
|
|
if (m_eTI==TI_IRowsetRefreshTRUE)
|
|
{
|
|
TESTC_(m_pChgIRowsetRefresh->RefreshVisibleData(DB_NULL_HCHAPTER,cRowsObtained, phRow, TRUE, &m_cRowsResynched,&m_rghRowsResynched, &m_rgRowStatus), S_OK);
|
|
}
|
|
else
|
|
{
|
|
TESTC_(m_pChgIRowsetRefresh->RefreshVisibleData(DB_NULL_HCHAPTER,cRowsObtained, phRow, FALSE, &m_cRowsResynched,&m_rghRowsResynched, &m_rgRowStatus), S_OK);
|
|
}
|
|
TESTC_(m_pChgIRowsetRefresh->GetLastVisibleData(phRow[ulArbitraryRowIdx], m_hChgAccessor, m_pResynchVisibleData), S_OK);
|
|
}
|
|
|
|
CompareOutParams(cRowsObtained, phRow);
|
|
//Row status should be OK for all rows.
|
|
for (i=0; i<cRowsObtained; i++)
|
|
{
|
|
if (g_fNOCHANGE)
|
|
{
|
|
//no change was made here, if the provider can handle it, expect it
|
|
COMPARE(m_rgRowStatus[i], DBROWSTATUS_S_NOCHANGE);
|
|
}
|
|
else
|
|
{
|
|
COMPARE(m_rgRowStatus[i], DBROWSTATUS_S_OK);
|
|
}
|
|
}
|
|
//Now get data that was resynch'd
|
|
TESTC_(m_pChgIRowset->GetData(phRow[ulArbitraryRowIdx], m_hChgAccessor, m_pResynchRowsetData), S_OK);
|
|
|
|
fResults = COMPARE(CompareBuffer(m_pRowsetData,pArbRowData,m_cBindings,m_rgBindings,m_pIMalloc,FALSE,FALSE,COMPARE_ONLY),TRUE);
|
|
fResults &= COMPARE(CompareBuffer(m_pResynchRowsetData,pArbRowData,m_cBindings,m_rgBindings,m_pIMalloc,FALSE,FALSE,COMPARE_ONLY),TRUE);
|
|
fResults &= COMPARE(CompareBuffer(m_pResynchVisibleData,pArbRowData,m_cBindings,m_rgBindings,m_pIMalloc,FALSE,FALSE,COMPARE_ONLY),TRUE);
|
|
CLEANUP:
|
|
FreeOutParams();
|
|
|
|
m_pChgIRowset->ReleaseRows(cRowsObtained, phRow, NULL, NULL, NULL);
|
|
|
|
if (pArbRowData)
|
|
PROVIDER_FREE(pArbRowData);
|
|
|
|
if (fResults)
|
|
return TEST_PASS;
|
|
else
|
|
return TEST_FAIL;
|
|
}
|
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Test Case Section
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
|
|
|
|
// {{ TCW_TEST_CASE_MAP(TCPropCanHoldRowsResynch)
|
|
//--------------------------------------------------------------------
|
|
// @class General Scenarios with CANHOLDROWS
|
|
//
|
|
class TCPropCanHoldRowsResynch : public CPropCanHoldRowsResynch {
|
|
public:
|
|
// @cmember Static array of variations
|
|
DECLARE_TEST_CASE_DATA();
|
|
|
|
public:
|
|
ISOLEVEL m_fHighestSupportedIsoLevel;
|
|
|
|
// {{ TCW_DECLARE_FUNCS
|
|
// @cmember Execution Routine
|
|
DECLARE_TEST_CASE_FUNCS(TCPropCanHoldRowsResynch,CPropCanHoldRowsResynch);
|
|
// }}
|
|
|
|
// @cmember Initialization Routine
|
|
virtual BOOL Init();
|
|
// @cmember Termination Routine
|
|
virtual BOOL Terminate();
|
|
|
|
// {{ TCW_TESTVARS()
|
|
// @cmember Isolation Level - Chaos
|
|
int Variation_1();
|
|
// @cmember Isolation Level - Read Uncommitted
|
|
int Variation_2();
|
|
// @cmember Isolation Level - Read Committed
|
|
int Variation_3();
|
|
// @cmember Isolation Level - Repeatable Read
|
|
int Variation_4();
|
|
// @cmember Isolation Level - Serializable
|
|
int Variation_5();
|
|
// @cmember Isolation Level - Unspecified
|
|
int Variation_6();
|
|
// @cmember Own Insert - Highest Isolation Level
|
|
int Variation_7();
|
|
// @cmember Variable Length Columns Only Bound
|
|
int Variation_8();
|
|
// @cmember Fixed Length Columns Only Bound
|
|
int Variation_9();
|
|
// @cmember All Columns Bound BYREF
|
|
int Variation_10();
|
|
// @cmember Own Update - Highest Isolation Level
|
|
int Variation_11();
|
|
// @cmember GetVisibleData with PASSBYREF - DB_E_BADACCESSORHANDLE
|
|
int Variation_12();
|
|
// @cmember GetVisibleData with PROVIDEROWNED - DB_E_BADACCESSORHANDLE
|
|
int Variation_13();
|
|
// @cmember ResynchRows/RefreshVisibleData with hRow = DB_NULL_HROW - DB_E_BADROWHANDLE
|
|
int Variation_14();
|
|
// @cmember ResynchRows/RefreshVisibleData with hRow = hard deleted - DB_E_DELETEDROW
|
|
int Variation_15();
|
|
// @cmember ResynchRows/RefreshVisibleData with hRow = row deleted by another txn - DB_E_DELETEDROW
|
|
int Variation_16();
|
|
// @cmember GetVisibleData with pData = NULL - E_INVALIDARG
|
|
int Variation_17();
|
|
// @cmember GetVisibleData with Null Accessor, pData = NULL
|
|
int Variation_18();
|
|
// @cmember GetVisibleData with Null Accessor, pData valid
|
|
int Variation_19();
|
|
// @cmember Fetch Position
|
|
int Variation_20();
|
|
// @cmember Rows 1 and n
|
|
int Variation_21();
|
|
// @cmember All Rows
|
|
int Variation_22();
|
|
// @cmember ResynchRows with rghRows = NULL - E_INVALIDARG
|
|
int Variation_23();
|
|
// @cmember ResynchRows with one invalid hRow - DBROWSTATUS_E_INVALID
|
|
int Variation_24();
|
|
// @cmember ResynchRows with all invalid hRows - DBROWSTATUS_E_INVALID
|
|
int Variation_25();
|
|
// @cmember ResynchRows with cRows = 0 and no active hRows
|
|
int Variation_26();
|
|
// @cmember ResynchRows/RefreshVisibleData with held hRows from different GetNextRows calls, cRows=0
|
|
int Variation_27();
|
|
// @cmember ResynchRows/RefreshVisibleData with held hRows from different GetNextRows calls, cRows exact
|
|
int Variation_28();
|
|
// @cmember Fetch Position with Read Only Rowset
|
|
int Variation_29();
|
|
// @cmember Rows 1 and n with Read Only Rowset
|
|
int Variation_30();
|
|
// @cmember All Rows with Read Only Rowset
|
|
int Variation_31();
|
|
// @cmember ResynchRows/RefreshVisibleData with hRow = DB_NULL_HROW - DB_E_BADROWHANDLE
|
|
int Variation_32();
|
|
// @cmember ResynchRows/RefreshVisibleData with held cRows=0 and all params NULL
|
|
int Variation_33();
|
|
// @cmember ResynchRows with one invalid hRow - no params
|
|
int Variation_34();
|
|
// @cmember ResynchRows/RefreshVisibleData with hRow = hard deleted - DB_E_DELETEDROW -NULLS
|
|
int Variation_35();
|
|
// @cmember ResynchRows/RefreshVisibleData with hRow = hard deleted - no params - no op
|
|
int Variation_36();
|
|
// @cmember GetVisibleData with released HROW - DB_E_BADROWHANDLE
|
|
int Variation_37();
|
|
// @cmember SetData with all status IGNORE
|
|
int Variation_38();
|
|
// @cmember SetData with all status DEFAULT
|
|
int Variation_39();
|
|
// @cmember InsertRows with all status DEFAULT
|
|
int Variation_40();
|
|
//
|
|
// }}
|
|
};
|
|
// {{ TCW_TESTCASE(TCPropCanHoldRowsResynch)
|
|
#define THE_CLASS TCPropCanHoldRowsResynch
|
|
BEG_TEST_CASE(TCPropCanHoldRowsResynch, CPropCanHoldRowsResynch, L"General Scenarios with CANHOLDROWS")
|
|
TEST_VARIATION(1, L"Isolation Level - Chaos")
|
|
TEST_VARIATION(2, L"Isolation Level - Read Uncommitted")
|
|
TEST_VARIATION(3, L"Isolation Level - Read Committed")
|
|
TEST_VARIATION(4, L"Isolation Level - Repeatable Read")
|
|
TEST_VARIATION(5, L"Isolation Level - Serializable")
|
|
TEST_VARIATION(6, L"Isolation Level - Unspecified")
|
|
TEST_VARIATION(7, L"Own Insert - Highest Isolation Level")
|
|
TEST_VARIATION(8, L"Variable Length Columns Only Bound")
|
|
TEST_VARIATION(9, L"Fixed Length Columns Only Bound")
|
|
TEST_VARIATION(10, L"All Columns Bound BYREF")
|
|
TEST_VARIATION(11, L"Own Update - Highest Isolation Level")
|
|
TEST_VARIATION(12, L"GetVisibleData with PASSBYREF - DB_E_BADACCESSORHANDLE")
|
|
TEST_VARIATION(13, L"GetVisibleData with PROVIDEROWNED - DB_E_BADACCESSORHANDLE")
|
|
TEST_VARIATION(14, L"ResynchRows/RefreshVisibleData with hRow = DB_NULL_HROW - DB_E_BADROWHANDLE")
|
|
TEST_VARIATION(15, L"ResynchRows/RefreshVisibleData with hRow = hard deleted - DB_E_DELETEDROW")
|
|
TEST_VARIATION(16, L"ResynchRows/RefreshVisibleData with hRow = row deleted by another txn - DB_E_DELETEDROW")
|
|
TEST_VARIATION(17, L"GetVisibleData with pData = NULL - E_INVALIDARG")
|
|
TEST_VARIATION(18, L"GetVisibleData with Null Accessor, pData = NULL")
|
|
TEST_VARIATION(19, L"GetVisibleData with Null Accessor, pData valid")
|
|
TEST_VARIATION(20, L"Fetch Position")
|
|
TEST_VARIATION(21, L"Rows 1 and n")
|
|
TEST_VARIATION(22, L"All Rows")
|
|
TEST_VARIATION(23, L"ResynchRows with rghRows = NULL - E_INVALIDARG")
|
|
TEST_VARIATION(24, L"ResynchRows with one invalid hRow - DBROWSTATUS_E_INVALID")
|
|
TEST_VARIATION(25, L"ResynchRows with all invalid hRows - DBROWSTATUS_E_INVALID")
|
|
TEST_VARIATION(26, L"ResynchRows with cRows = 0 and no active hRows")
|
|
TEST_VARIATION(27, L"ResynchRows/RefreshVisibleData with held hRows from different GetNextRows calls, cRows=0")
|
|
TEST_VARIATION(28, L"ResynchRows/RefreshVisibleData with held hRows from different GetNextRows calls, cRows exact")
|
|
TEST_VARIATION(29, L"Fetch Position with Read Only Rowset")
|
|
TEST_VARIATION(30, L"Rows 1 and n with Read Only Rowset")
|
|
TEST_VARIATION(31, L"All Rows with Read Only Rowset")
|
|
TEST_VARIATION(32, L"ResynchRows/RefreshVisibleData with hRow = DB_NULL_HROW - DB_E_BADROWHANDLE")
|
|
TEST_VARIATION(33, L"ResynchRows/RefreshVisibleData with held cRows=0 and all params NULL")
|
|
TEST_VARIATION(34, L"ResynchRows with one invalid hRow - no params")
|
|
TEST_VARIATION(35, L"ResynchRows/RefreshVisibleData with hRow = hard deleted - DB_E_DELETEDROW -NULLS")
|
|
TEST_VARIATION(36, L"ResynchRows/RefreshVisibleData with hRow = hard deleted - no params - no op")
|
|
TEST_VARIATION(37, L"GetVisibleData with released HROW - DB_E_BADROWHANDLE")
|
|
TEST_VARIATION(38, L"SetData with all status IGNORE")
|
|
TEST_VARIATION(39, L"SetData with all status DEFAULT")
|
|
TEST_VARIATION(40, L"InsertRows with all status DEFAULT")
|
|
END_TEST_CASE()
|
|
#undef THE_CLASS
|
|
// }}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_TEST_CASE_MAP(TCPropNoHoldRowsResynch)
|
|
//--------------------------------------------------------------------
|
|
// @class Rowset without CANHOLDROWS
|
|
//
|
|
class TCPropNoHoldRowsResynch : public CResynchRefresh {
|
|
public:
|
|
// @cmember Static array of variations
|
|
DECLARE_TEST_CASE_DATA();
|
|
|
|
public:
|
|
// {{ TCW_DECLARE_FUNCS
|
|
// @cmember Execution Routine
|
|
DECLARE_TEST_CASE_FUNCS(TCPropNoHoldRowsResynch,CResynchRefresh);
|
|
// }}
|
|
|
|
// @cmember Initialization Routine
|
|
virtual BOOL Init();
|
|
// @cmember Termination Routine
|
|
virtual BOOL Terminate();
|
|
|
|
// {{ TCW_TESTVARS()
|
|
// @cmember Read Only Rowset without DBPROP_CANHOLDROWS
|
|
int Variation_1();
|
|
// @cmember Changeable Rowset without DBPROP_CANHOLDROWS
|
|
int Variation_2();
|
|
// }}
|
|
};
|
|
// {{ TCW_TESTCASE(TCPropNoHoldRowsResynch)
|
|
#define THE_CLASS TCPropNoHoldRowsResynch
|
|
BEG_TEST_CASE(TCPropNoHoldRowsResynch, CResynchRefresh, L"Rowset without CANHOLDROWS")
|
|
TEST_VARIATION(1, L"Read Only Rowset without DBPROP_CANHOLDROWS")
|
|
TEST_VARIATION(2, L"Changeable Rowset without DBPROP_CANHOLDROWS")
|
|
END_TEST_CASE()
|
|
#undef THE_CLASS
|
|
// }}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_TEST_CASE_MAP(TCPropBookmarksResynch)
|
|
//--------------------------------------------------------------------
|
|
// @class Rowset with BOOKMARKS
|
|
//
|
|
class TCPropBookmarksResynch : public CResynchRefresh {
|
|
public:
|
|
// @cmember Static array of variations
|
|
DECLARE_TEST_CASE_DATA();
|
|
|
|
public:
|
|
// {{ TCW_DECLARE_FUNCS
|
|
// @cmember Execution Routine
|
|
DECLARE_TEST_CASE_FUNCS(TCPropBookmarksResynch,CResynchRefresh);
|
|
// }}
|
|
|
|
// @cmember Initialization Routine
|
|
virtual BOOL Init();
|
|
// @cmember Termination Routine
|
|
virtual BOOL Terminate();
|
|
|
|
// {{ TCW_TESTVARS()
|
|
// @cmember Read Only Rowset with DBPROP_BOOKMARKS
|
|
int Variation_1();
|
|
// @cmember Changeable Rowset with DBPROP_BOOKMARKS
|
|
int Variation_2();
|
|
// }}
|
|
};
|
|
// {{ TCW_TESTCASE(TCPropBookmarksResynch)
|
|
#define THE_CLASS TCPropBookmarksResynch
|
|
BEG_TEST_CASE(TCPropBookmarksResynch, CResynchRefresh, L"Rowset with BOOKMARKS")
|
|
TEST_VARIATION(1, L"Read Only Rowset with DBPROP_BOOKMARKS")
|
|
TEST_VARIATION(2, L"Changeable Rowset with DBPROP_BOOKMARKS")
|
|
END_TEST_CASE()
|
|
#undef THE_CLASS
|
|
// }}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_TEST_CASE_MAP(TCPropDeferredResynch)
|
|
//--------------------------------------------------------------------
|
|
// @class Rowset with CANHOLDROWS and DEFERRED
|
|
//
|
|
class TCPropDeferredResynch : public CResynchRefresh {
|
|
public:
|
|
// @cmember Static array of variations
|
|
DECLARE_TEST_CASE_DATA();
|
|
|
|
public:
|
|
// {{ TCW_DECLARE_FUNCS
|
|
// @cmember Execution Routine
|
|
DECLARE_TEST_CASE_FUNCS(TCPropDeferredResynch,CResynchRefresh);
|
|
// }}
|
|
|
|
// @cmember Initialization Routine
|
|
virtual BOOL Init();
|
|
// @cmember Termination Routine
|
|
virtual BOOL Terminate();
|
|
|
|
// {{ TCW_TESTVARS()
|
|
// @cmember Read Only Rowset with DBPROP_DEFERRED
|
|
int Variation_1();
|
|
// @cmember Changeable Rowset with DBPROP_DEFERRED
|
|
int Variation_2();
|
|
// }}
|
|
//flag to chekc if the Init for this class passed
|
|
BOOL m_fInitPass;
|
|
};
|
|
// {{ TCW_TESTCASE(TCPropDeferredResynch)
|
|
#define THE_CLASS TCPropDeferredResynch
|
|
BEG_TEST_CASE(TCPropDeferredResynch, CResynchRefresh, L"Rowset with CANHOLDROWS and DEFERRED ")
|
|
TEST_VARIATION(1, L"Read Only Rowset with DBPROP_DEFERRED")
|
|
TEST_VARIATION(2, L"Changeable Rowset with DBPROP_DEFERRED")
|
|
END_TEST_CASE()
|
|
#undef THE_CLASS
|
|
// }}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_TEST_CASE_MAP(TCPropCacheDeferredResynch)
|
|
//--------------------------------------------------------------------
|
|
// @class Rowset with CACHEDEFERRED
|
|
//
|
|
class TCPropCacheDeferredResynch : public CResynchRefresh {
|
|
public:
|
|
// @cmember Static array of variations
|
|
DECLARE_TEST_CASE_DATA();
|
|
|
|
public:
|
|
// {{ TCW_DECLARE_FUNCS
|
|
// @cmember Execution Routine
|
|
DECLARE_TEST_CASE_FUNCS(TCPropCacheDeferredResynch,CResynchRefresh);
|
|
// }}
|
|
|
|
// @cmember Initialization Routine
|
|
virtual BOOL Init();
|
|
// @cmember Termination Routine
|
|
virtual BOOL Terminate();
|
|
|
|
// {{ TCW_TESTVARS()
|
|
// @cmember Read Only Rowset with DBPROP_CACHEDEFERRED
|
|
int Variation_1();
|
|
// @cmember Changeable Rowset with DBPROP_CACHEDEFERRED
|
|
int Variation_2();
|
|
//flag to check if the Init for this class passed
|
|
BOOL m_fInitPass;
|
|
// }}
|
|
};
|
|
// {{ TCW_TESTCASE(TCPropCacheDeferredResynch)
|
|
#define THE_CLASS TCPropCacheDeferredResynch
|
|
BEG_TEST_CASE(TCPropCacheDeferredResynch, CResynchRefresh, L"Rowset with CACHEDEFERRED")
|
|
TEST_VARIATION(1, L"Read Only Rowset with DBPROP_CACHEDEFERRED")
|
|
TEST_VARIATION(2, L"Changeable Rowset with DBPROP_CACHEDEFERRED")
|
|
END_TEST_CASE()
|
|
#undef THE_CLASS
|
|
// }}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_TEST_CASE_MAP(TCPropUpdateResynch)
|
|
//--------------------------------------------------------------------
|
|
// @class Rowset with IRowsetUpdate
|
|
//
|
|
class TCPropUpdateResynch : public CResynchRefresh {
|
|
public:
|
|
// @cmember Static array of variations
|
|
DECLARE_TEST_CASE_DATA();
|
|
|
|
public:
|
|
// {{ TCW_DECLARE_FUNCS
|
|
// @cmember Execution Routine
|
|
DECLARE_TEST_CASE_FUNCS(TCPropUpdateResynch,CResynchRefresh);
|
|
// }}
|
|
|
|
//@cmember IRowsetUpdate interface on Chg Rowset
|
|
IRowsetUpdate *m_pChgIRowsetUpdate1;
|
|
IRowsetUpdate *m_pChgIRowsetUpdate2;
|
|
|
|
// @cmember Initialization Routine
|
|
virtual BOOL Init();
|
|
// @cmember Termination Routine
|
|
virtual BOOL Terminate();
|
|
|
|
// {{ TCW_TESTVARS()
|
|
// @cmember Soft deleted row
|
|
int Variation_1();
|
|
// @cmember Soft inserted row
|
|
int Variation_2();
|
|
// @cmember Soft changed row
|
|
int Variation_3();
|
|
// @cmember Inserted row after Update
|
|
int Variation_4();
|
|
// @cmember Pending change
|
|
int Variation_5();
|
|
// @cmember GetOriginalData
|
|
int Variation_6();
|
|
// @cmember Pending Insert
|
|
int Variation_7();
|
|
// @cmember Pending Delete
|
|
int Variation_8();
|
|
// @cmember Insert, change and delete on a rowset
|
|
int Variation_9();
|
|
// }}
|
|
};
|
|
// {{ TCW_TESTCASE(TCPropUpdateResynch)
|
|
#define THE_CLASS TCPropUpdateResynch
|
|
BEG_TEST_CASE(TCPropUpdateResynch, CResynchRefresh, L"Rowset with IRowsetUpdate")
|
|
TEST_VARIATION(1, L"Soft deleted row")
|
|
TEST_VARIATION(2, L"Soft inserted row")
|
|
TEST_VARIATION(3, L"Soft changed row")
|
|
TEST_VARIATION(4, L"Inserted row after Update")
|
|
TEST_VARIATION(5, L"Pending change")
|
|
TEST_VARIATION(6, L"GetOriginalData")
|
|
TEST_VARIATION(7, L"Pending Insert")
|
|
TEST_VARIATION(8, L"Pending Delete")
|
|
TEST_VARIATION(9, L"Insert, change and delete on a rowset")
|
|
END_TEST_CASE()
|
|
#undef THE_CLASS
|
|
// }}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_TEST_CASE_MAP(TCZombieResynch)
|
|
//--------------------------------------------------------------------
|
|
// @class Rowset Preservation tests
|
|
//
|
|
class TCZombieResynch : public CTransaction, public TCBase
|
|
{
|
|
public:
|
|
// @cmember Static array of variations
|
|
DECLARE_TEST_CASE_DATA();
|
|
|
|
public:
|
|
|
|
//@cmember Property set for rowset properties
|
|
DBPROPSET m_PropSet;
|
|
//@cmember Property struct for ResynchRows/RefreshVisibleData
|
|
DBPROP m_DBProp;
|
|
//@cmember Accessor
|
|
HACCESSOR m_hAccessor;
|
|
//@cmember Count of bindings
|
|
DBCOUNTITEM m_cBindings;
|
|
//@cmember Array of bindings
|
|
DBBINDING *m_rgBindings;
|
|
//@cmember Size of row
|
|
DBLENGTH m_cbRowSize;
|
|
|
|
//@cmember hRow
|
|
HROW m_hRow;
|
|
//@cmember Bogus data buffer
|
|
BYTE *m_pData;
|
|
|
|
// {{ TCW_DECLARE_FUNCS
|
|
// @cmember Execution Routine
|
|
DECLARE_TEST_CASE_FUNCS(TCZombieResynch,CTransaction);
|
|
// }}
|
|
|
|
|
|
// @cmember Initialization Routine
|
|
virtual BOOL Init();
|
|
// @cmember Termination Routine
|
|
virtual BOOL Terminate();
|
|
//@cmember Helper function for all rowset preservation testing
|
|
//with respect to ResynchRows/RefreshVisibleData
|
|
int TCZombieResynch::TestZombie(ETXN eTxn, BOOL fRetaining);
|
|
|
|
// {{ TCW_TESTVARS()
|
|
// @cmember Commit with fRetaining = TRUE
|
|
int Variation_1();
|
|
// @cmember Commit with fRetaining = FALSE
|
|
int Variation_2();
|
|
// @cmember Abort with fRetaining = TRUE
|
|
int Variation_3();
|
|
// @cmember Abort with fRetaining = FALSE
|
|
int Variation_4();
|
|
// }}
|
|
};
|
|
// {{ TCW_TESTCASE(TCZombieResynch)
|
|
#define THE_CLASS TCZombieResynch
|
|
BEG_TEST_CASE(TCZombieResynch, CTransaction, L"Rowset Preservation tests")
|
|
TEST_VARIATION(1, L"Commit with fRetaining = TRUE")
|
|
TEST_VARIATION(2, L"Commit with fRetaining = FALSE")
|
|
TEST_VARIATION(3, L"Abort with fRetaining = TRUE")
|
|
TEST_VARIATION(4, L"Abort with fRetaining = FALSE")
|
|
END_TEST_CASE()
|
|
#undef THE_CLASS
|
|
// }}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_TEST_CASE_MAP(TCExtendedErrorsResynch)
|
|
//--------------------------------------------------------------------
|
|
// @class Extended Errors
|
|
//
|
|
class TCExtendedErrorsResynch : public CResynchRefresh {
|
|
public:
|
|
// @cmember Static array of variations
|
|
DECLARE_TEST_CASE_DATA();
|
|
|
|
//@cmember Extended error object
|
|
//CExtError * m_pExtError;
|
|
|
|
public:
|
|
// {{ TCW_DECLARE_FUNCS
|
|
// @cmember Execution Routine
|
|
DECLARE_TEST_CASE_FUNCS(TCExtendedErrorsResynch,CResynchRefresh);
|
|
// }}
|
|
|
|
|
|
// @cmember Initialization Routine
|
|
virtual BOOL Init();
|
|
// @cmember Termination Routine
|
|
virtual BOOL Terminate();
|
|
|
|
// {{ TCW_TESTVARS()
|
|
// @cmember Valid ResynchRows/RefreshVisibleData calls with previous error object existing.
|
|
int Variation_1();
|
|
// @cmember Invalid GetVisibleData call with previous error object existing
|
|
int Variation_2();
|
|
// @cmember Invalid ResynchRows call with previous error object existing
|
|
int Variation_3();
|
|
// @cmember Invalid ResynchRows/RefreshVisibleData calls no with previous error object existing
|
|
int Variation_4();
|
|
// @cmember Invalid ResynchRows/RefreshVisibleData - E_INVALIDARG
|
|
int Variation_5();
|
|
// @cmember pcRowsRefreshed - NULL, ignore prghRowsRefreshed
|
|
int Variation_6();
|
|
// }}
|
|
};
|
|
// {{ TCW_TESTCASE(TCExtendedErrorsResynch)
|
|
#define THE_CLASS TCExtendedErrorsResynch
|
|
BEG_TEST_CASE(TCExtendedErrorsResynch, CResynchRefresh, L"Extended Errors")
|
|
TEST_VARIATION(1, L"Valid ResynchRows/RefreshVisibleData calls with previous error object existing.")
|
|
TEST_VARIATION(2, L"Invalid GetVisibleData call with previous error object existing")
|
|
TEST_VARIATION(3, L"Invalid ResynchRows call with previous error object existing")
|
|
TEST_VARIATION(4, L"Invalid ResynchRows/RefreshVisibleData calls no with previous error object existing")
|
|
TEST_VARIATION(5, L"Invalid ResynchRows - E_INVALIDARG")
|
|
TEST_VARIATION(6, L"pcRowsRefreshed - NULL, ignore prghRowsRefreshed")
|
|
END_TEST_CASE()
|
|
#undef THE_CLASS
|
|
// }}
|
|
// }}
|
|
|
|
// {{ TCW_TEST_CASE_MAP(TCPropResynchOnlyResynch)
|
|
//--------------------------------------------------------------------
|
|
// @class Rowsets with only ResynchRows/RefreshVisibleData Requested
|
|
//
|
|
class TCPropResynchOnlyResynch : public CResynchRefresh {
|
|
public:
|
|
// @cmember Static array of variations
|
|
DECLARE_TEST_CASE_DATA();
|
|
|
|
public:
|
|
// {{ TCW_DECLARE_FUNCS
|
|
// @cmember Execution Routine
|
|
DECLARE_TEST_CASE_FUNCS(TCPropResynchOnlyResynch,CResynchRefresh);
|
|
// }}
|
|
|
|
// @cmember Initialization Routine
|
|
virtual BOOL Init();
|
|
// @cmember Termination Routine
|
|
virtual BOOL Terminate();
|
|
|
|
// {{ TCW_TESTVARS()
|
|
// @cmember Read only rowset with Resynch Only
|
|
int Variation_1();
|
|
// @cmember Changeable rowset with Resynch Only
|
|
int Variation_2();
|
|
// }}
|
|
};
|
|
// {{ TCW_TESTCASE(TCPropResynchOnlyResynch)
|
|
#define THE_CLASS TCPropResynchOnlyResynch
|
|
BEG_TEST_CASE(TCPropResynchOnlyResynch, CResynchRefresh, L"Rowsets with only ResynchRows/RefreshVisibleData Requested")
|
|
TEST_VARIATION(1, L"Read only rowset with Resynch Only")
|
|
TEST_VARIATION(2, L"Changeable rowset with Resynch Only")
|
|
END_TEST_CASE()
|
|
#undef THE_CLASS
|
|
// }}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_TEST_CASE_MAP(TCPropCanHoldRowsResynchBLOBS)
|
|
//--------------------------------------------------------------------
|
|
// @class CanHoldRows testcases using BLOB data
|
|
//
|
|
class TCPropCanHoldRowsResynchBLOBS : public CPropCanHoldRowsResynch {
|
|
public:
|
|
// @cmember Static array of variations
|
|
DECLARE_TEST_CASE_DATA();
|
|
|
|
public:
|
|
|
|
ISOLEVEL m_fHighestSupportedIsoLevel;
|
|
|
|
// {{ TCW_DECLARE_FUNCS
|
|
// @cmember Execution Routine
|
|
DECLARE_TEST_CASE_FUNCS(TCPropCanHoldRowsResynchBLOBS,CPropCanHoldRowsResynch);
|
|
// }}
|
|
|
|
// @cmember Initialization Routine
|
|
virtual BOOL Init();
|
|
// @cmember Termination Routine
|
|
virtual BOOL Terminate();
|
|
|
|
// {{ TCW_TESTVARS()
|
|
// @cmember Isolation Level - Chaos
|
|
int Variation_1();
|
|
// @cmember Isolation Level - Read Uncommitted
|
|
int Variation_2();
|
|
// @cmember Isolation Level - Read Committed
|
|
int Variation_3();
|
|
// @cmember Isolation Level - Repeatable Read
|
|
int Variation_4();
|
|
// @cmember Isolation Level - Serializable
|
|
int Variation_5();
|
|
// @cmember Isolation Level - Unspecified
|
|
int Variation_6();
|
|
// @cmember Own Insert - Highest Isolation Level
|
|
int Variation_7();
|
|
// @cmember Variable Length Columns Only Bound
|
|
int Variation_8();
|
|
// @cmember Fixed Length Columns Only Bound
|
|
int Variation_9();
|
|
// @cmember All Columns Bound BYREF
|
|
int Variation_10();
|
|
// @cmember Own Update - Highest Isolation Level
|
|
int Variation_11();
|
|
// @cmember GetVisibleData with PASSBYREF - DB_E_BADACCESSORHANDLE
|
|
int Variation_12();
|
|
// @cmember GetVisibleData with PROVIDEROWNED - DB_E_BADACCESSORHANDLE
|
|
int Variation_13();
|
|
// @cmember ResynchRows/RefreshVisibleData with hRow = DB_NULL_HROW - DB_E_BADROWHANDLE
|
|
int Variation_14();
|
|
// @cmember ResynchRows/RefreshVisibleData with hRow = hard deleted - DB_E_DELETEDROW
|
|
int Variation_15();
|
|
// @cmember ResynchRows/RefreshVisibleData with hRow = row deleted by another txn - DB_E_DELETEDROW
|
|
int Variation_16();
|
|
// @cmember GetVisibleData with pData = NULL - E_INVALIDARG
|
|
int Variation_17();
|
|
// @cmember GetVisibleData with Null Accessor, pData = NULL
|
|
int Variation_18();
|
|
// @cmember GetVisibleData with Null Accessor, pData valid
|
|
int Variation_19();
|
|
// @cmember Fetch Position
|
|
int Variation_20();
|
|
// @cmember Rows 1 and n
|
|
int Variation_21();
|
|
// @cmember All Rows
|
|
int Variation_22();
|
|
// @cmember ResynchRows with rghRows = NULL - E_INVALIDARG
|
|
int Variation_23();
|
|
// @cmember ResynchRows with one invalid hRow - DBROWSTATUS_E_INVALID
|
|
int Variation_24();
|
|
// @cmember ResynchRows with all invalid hRows - DBROWSTATUS_E_INVALID
|
|
int Variation_25();
|
|
// @cmember ResynchRows with cRows = 0 and no active hRows
|
|
int Variation_26();
|
|
// @cmember ResynchRows/RefreshVisibleData with held hRows from different GetNextRows calls, cRows=0
|
|
int Variation_27();
|
|
// @cmember ResynchRows/RefreshVisibleData with held hRows from different GetNextRows calls, cRows exact
|
|
int Variation_28();
|
|
// @cmember Fetch Position with Read Only Rowset
|
|
int Variation_29();
|
|
// @cmember Rows 1 and n with Read Only Rowset
|
|
int Variation_30();
|
|
// @cmember All Rows with Read Only Rowset
|
|
int Variation_31();
|
|
// }}
|
|
};
|
|
// {{ TCW_TESTCASE(TCPropCanHoldRowsResynchBLOBS)
|
|
#define THE_CLASS TCPropCanHoldRowsResynchBLOBS
|
|
BEG_TEST_CASE(TCPropCanHoldRowsResynchBLOBS, CPropCanHoldRowsResynch, L"CanHoldRows testcases using BLOB data")
|
|
TEST_VARIATION(1, L"Isolation Level - Chaos")
|
|
TEST_VARIATION(2, L"Isolation Level - Read Uncommitted")
|
|
TEST_VARIATION(3, L"Isolation Level - Read Committed")
|
|
TEST_VARIATION(4, L"Isolation Level - Repeatable Read")
|
|
TEST_VARIATION(5, L"Isolation Level - Serializable")
|
|
TEST_VARIATION(6, L"Isolation Level - Unspecified")
|
|
TEST_VARIATION(7, L"Own Insert - Highest Isolation Level")
|
|
TEST_VARIATION(8, L"Variable Length Columns Only Bound")
|
|
TEST_VARIATION(9, L"Fixed Length Columns Only Bound")
|
|
TEST_VARIATION(10, L"All Columns Bound BYREF")
|
|
TEST_VARIATION(11, L"Own Update - Highest Isolation Level")
|
|
TEST_VARIATION(12, L"GetVisibleData with PASSBYREF - DB_E_BADACCESSORHANDLE")
|
|
TEST_VARIATION(13, L"GetVisibleData with PROVIDEROWNED - DB_E_BADACCESSORHANDLE")
|
|
TEST_VARIATION(14, L"ResynchRows/RefreshVisibleData with hRow = DB_NULL_HROW - DB_E_BADROWHANDLE")
|
|
TEST_VARIATION(15, L"ResynchRows/RefreshVisibleData with hRow = hard deleted - DB_E_DELETEDROW")
|
|
TEST_VARIATION(16, L"ResynchRows/RefreshVisibleData with hRow = row deleted by another txn - DB_E_DELETEDROW")
|
|
TEST_VARIATION(17, L"GetVisibleData with pData = NULL - E_INVALIDARG")
|
|
TEST_VARIATION(18, L"GetVisibleData with Null Accessor, pData = NULL")
|
|
TEST_VARIATION(19, L"GetVisibleData with Null Accessor, pData valid")
|
|
TEST_VARIATION(20, L"Fetch Position")
|
|
TEST_VARIATION(21, L"Rows 1 and n")
|
|
TEST_VARIATION(22, L"All Rows")
|
|
TEST_VARIATION(23, L"ResynchRows with rghRows = NULL - E_INVALIDARG")
|
|
TEST_VARIATION(24, L"ResynchRows with one invalid hRow - DBROWSTATUS_E_INVALID")
|
|
TEST_VARIATION(25, L"ResynchRows with all invalid hRows - DBROWSTATUS_E_INVALID")
|
|
TEST_VARIATION(26, L"ResynchRows with cRows = 0 and no active hRows")
|
|
TEST_VARIATION(27, L"ResynchRows/RefreshVisibleData with held hRows from different GetNextRows calls, cRows=0")
|
|
TEST_VARIATION(28, L"ResynchRows/RefreshVisibleData with held hRows from different GetNextRows calls, cRows exact")
|
|
TEST_VARIATION(29, L"Fetch Position with Read Only Rowset")
|
|
TEST_VARIATION(30, L"Rows 1 and n with Read Only Rowset")
|
|
TEST_VARIATION(31, L"All Rows with Read Only Rowset")
|
|
END_TEST_CASE()
|
|
#undef THE_CLASS
|
|
// }}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_TEST_CASE_MAP(TCNullRowResynch)
|
|
//--------------------------------------------------------------------
|
|
// @class Tests Resych with all NULLs
|
|
//
|
|
class TCNullRowResynch : public CRowsetObject, public TCBase
|
|
{
|
|
public:
|
|
// @cmember Static array of variations
|
|
DECLARE_TEST_CASE_DATA();
|
|
|
|
public:
|
|
// {{ TCW_DECLARE_FUNCS
|
|
// @cmember Execution Routine
|
|
DECLARE_TEST_CASE_FUNCS(TCNullRowResynch,CRowsetObject);
|
|
// }}
|
|
|
|
ITransactionLocal *m_pITransactionLocal;
|
|
DBBINDING *m_rgBindings;
|
|
DBCOUNTITEM m_cBindings;
|
|
DBLENGTH m_cbRowSize;
|
|
HACCESSOR m_hAccessor;
|
|
BYTE *m_pData;
|
|
IRowset *m_pIRowset;
|
|
HROW m_hRow;
|
|
HROW *m_phRow;
|
|
|
|
// @cmember Initialization Routine
|
|
virtual BOOL Init();
|
|
// @cmember Termination Routine
|
|
virtual BOOL Terminate();
|
|
|
|
// {{ TCW_TESTVARS()
|
|
// @cmember Resynch on Null row
|
|
int Variation_1();
|
|
// }}
|
|
};
|
|
// {{ TCW_TESTCASE(TCNullRowResynch)
|
|
#define THE_CLASS TCNullRowResynch
|
|
BEG_TEST_CASE(TCNullRowResynch, CRowsetObject, L"Tests Resych with all NULLs")
|
|
TEST_VARIATION(1, L"Resynch on Null row")
|
|
END_TEST_CASE()
|
|
#undef THE_CLASS
|
|
// }} TCW_TESTCASE_END
|
|
// }} TCW_TEST_CASE_MAP_END
|
|
|
|
|
|
// {{ TCW_TEST_CASE_MAP(TCMiscResynch)
|
|
//--------------------------------------------------------------------
|
|
// @class Misc Resych Tests
|
|
//
|
|
class TCMiscResynch : public CRowsetObject, public TCBase
|
|
{
|
|
public:
|
|
// @cmember Static array of variations
|
|
DECLARE_TEST_CASE_DATA();
|
|
|
|
public:
|
|
// {{ TCW_DECLARE_FUNCS
|
|
// @cmember Execution Routine
|
|
DECLARE_TEST_CASE_FUNCS(TCMiscResynch,CRowsetObject);
|
|
// }}
|
|
|
|
CTable *m_pMiscTable;
|
|
IRowset *m_pIRowset;
|
|
HROW m_hRow;
|
|
HROW *m_phRow;
|
|
|
|
// @cmember Initialization Routine
|
|
virtual BOOL Init();
|
|
// @cmember Termination Routine
|
|
virtual BOOL Terminate();
|
|
|
|
// {{ TCW_TESTVARS()
|
|
// @cmember Resynch on a row with computed columns
|
|
int Variation_1();
|
|
// @cmember different accessors
|
|
int Variation_2();
|
|
// @cmember OTHERUPDATEDELETE - FALSE
|
|
int Variation_3();
|
|
// @cmember Resynch & Refresh on the same rowset
|
|
int Variation_4();
|
|
// @cmember GetVisible twice w/BLOBs
|
|
int Variation_5();
|
|
// }}
|
|
};
|
|
// {{ TCW_TESTCASE(TCMiscResynch)
|
|
#define THE_CLASS TCMiscResynch
|
|
BEG_TEST_CASE(TCMiscResynch, CRowsetObject, L"Misc Resych Tests")
|
|
TEST_VARIATION(1, L"Resynch on a row with computed columns")
|
|
TEST_VARIATION(2, L"Different accessors")
|
|
TEST_VARIATION(3, L"OTHERUPDATEDELETE - FALSE")
|
|
TEST_VARIATION(4, L"GetVisible twice w/BLOBs")
|
|
END_TEST_CASE()
|
|
#undef THE_CLASS
|
|
// }} TCW_TESTCASE_END
|
|
// }} TCW_TEST_CASE_MAP_END
|
|
|
|
|
|
// }} END_DECLARE_TEST_CASES()
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
// Copying Test Cases to make duplicate ones.
|
|
//
|
|
////////////////////////////////////////////////////////////////////////
|
|
#define COPY_TEST_CASE(theClass, baseClass) \
|
|
class theClass : public baseClass \
|
|
{ \
|
|
public: \
|
|
static const WCHAR m_wszTestCaseName[]; \
|
|
DECLARE_TEST_CASE_FUNCS(theClass, baseClass); \
|
|
}; \
|
|
const WCHAR theClass::m_wszTestCaseName[] = { L#theClass }; \
|
|
|
|
|
|
#define TEST_CASE_WITH_PARAM(iCase, theClass, param) \
|
|
case iCase: \
|
|
pCTestCase = new theClass(NULL); \
|
|
((theClass*)pCTestCase)->SetTestCaseParam(param); \
|
|
pCTestCase->SetOwningMod(iCase-1, pCThisTestModule); \
|
|
return pCTestCase;
|
|
|
|
//12-22
|
|
COPY_TEST_CASE(TCPropCanHoldRowsRefreshTRUE, TCPropCanHoldRowsResynch)
|
|
COPY_TEST_CASE(TCPropNoHoldRowsRefreshTRUE, TCPropNoHoldRowsResynch)
|
|
COPY_TEST_CASE(TCPropBookmarksRefreshTRUE, TCPropBookmarksResynch)
|
|
COPY_TEST_CASE(TCPropDeferredRefreshTRUE, TCPropDeferredResynch)
|
|
COPY_TEST_CASE(TCPropCacheDeferredRefreshTRUE, TCPropCacheDeferredResynch)
|
|
COPY_TEST_CASE(TCPropUpdateRefreshTRUE, TCPropUpdateResynch)
|
|
COPY_TEST_CASE(TCZombieRefreshTRUE, TCZombieResynch)
|
|
COPY_TEST_CASE(TCExtendedErrorsRefreshTRUE, TCExtendedErrorsResynch)
|
|
COPY_TEST_CASE(TCPropRefreshOnlyRefreshTRUE, TCPropResynchOnlyResynch)
|
|
COPY_TEST_CASE(TCPropCanHoldRowsRefreshTRUEBLOBS, TCPropCanHoldRowsResynchBLOBS)
|
|
COPY_TEST_CASE(TCNullRowRefreshTRUE, TCNullRowResynch)
|
|
COPY_TEST_CASE(TCMiscRefreshTRUE, TCMiscResynch)
|
|
|
|
//23-33
|
|
COPY_TEST_CASE(TCPropCanHoldRowsRefreshFALSE, TCPropCanHoldRowsResynch)
|
|
COPY_TEST_CASE(TCPropNoHoldRowsRefreshFALSE, TCPropNoHoldRowsResynch)
|
|
COPY_TEST_CASE(TCPropBookmarksRefreshFALSE, TCPropBookmarksResynch)
|
|
COPY_TEST_CASE(TCPropDeferredRefreshFALSE, TCPropDeferredResynch)
|
|
COPY_TEST_CASE(TCPropCacheDeferredRefreshFALSE, TCPropCacheDeferredResynch)
|
|
COPY_TEST_CASE(TCPropUpdateRefreshFALSE, TCPropUpdateResynch)
|
|
COPY_TEST_CASE(TCZombieRefreshFALSE, TCZombieResynch)
|
|
COPY_TEST_CASE(TCExtendedErrorsRefreshFALSE, TCExtendedErrorsResynch)
|
|
COPY_TEST_CASE(TCPropRefreshOnlyRefreshFALSE, TCPropResynchOnlyResynch)
|
|
COPY_TEST_CASE(TCPropCanHoldRowsRefreshFALSEBLOBS, TCPropCanHoldRowsResynchBLOBS)
|
|
COPY_TEST_CASE(TCNullRowRefreshFALSE, TCNullRowResynch)
|
|
COPY_TEST_CASE(TCMiscRefreshFALSE, TCMiscResynch)
|
|
|
|
#if 0
|
|
// {{ TCW_TESTMODULE(ThisModule)
|
|
TEST_MODULE(11, ThisModule, gwszModuleDescrip)
|
|
TEST_CASE(1, TCPropCanHoldRowsResynch)
|
|
TEST_CASE(2, TCPropNoHoldRowsResynch)
|
|
TEST_CASE(3, TCPropBookmarksResynch)
|
|
TEST_CASE(4, TCPropDeferredResynch)
|
|
TEST_CASE(5, TCPropCacheDeferredResynch)
|
|
TEST_CASE(6, TCPropUpdateResynch)
|
|
TEST_CASE(7, TCZombieResynch)
|
|
TEST_CASE(8, TCExtendedErrorsResynch)
|
|
TEST_CASE(9, TCPropResynchOnlyResynch)
|
|
TEST_CASE(10, TCPropCanHoldRowsResynchBLOBS)
|
|
TEST_CASE(11, TCNullRowResynch)
|
|
TEST_CASE(12, TCMiscResynch)// TEST_CASE(12, TCMiscResynch)
|
|
END_TEST_MODULE()
|
|
// }} TCW_TESTMODULE_END
|
|
#else
|
|
TEST_MODULE(36, ThisModule, gwszModuleDescrip)
|
|
TEST_CASE(1, TCPropCanHoldRowsResynch)
|
|
TEST_CASE(2, TCPropNoHoldRowsResynch)
|
|
TEST_CASE(3, TCPropBookmarksResynch)
|
|
TEST_CASE(4, TCPropDeferredResynch)
|
|
TEST_CASE(5, TCPropCacheDeferredResynch)
|
|
TEST_CASE(6, TCPropUpdateResynch)
|
|
TEST_CASE(7, TCZombieResynch)
|
|
TEST_CASE(8, TCExtendedErrorsResynch)
|
|
TEST_CASE(9, TCPropResynchOnlyResynch)
|
|
TEST_CASE(10, TCPropCanHoldRowsResynchBLOBS)
|
|
TEST_CASE(11, TCNullRowResynch)
|
|
TEST_CASE(12, TCMiscResynch)
|
|
//switch which interface is used here
|
|
TEST_CASE_WITH_PARAM(13, TCPropCanHoldRowsRefreshTRUE, TI_IRowsetRefreshTRUE)
|
|
TEST_CASE_WITH_PARAM(14, TCPropNoHoldRowsRefreshTRUE, TI_IRowsetRefreshTRUE)
|
|
TEST_CASE_WITH_PARAM(15, TCPropBookmarksRefreshTRUE, TI_IRowsetRefreshTRUE)
|
|
TEST_CASE_WITH_PARAM(16, TCPropDeferredRefreshTRUE, TI_IRowsetRefreshTRUE)
|
|
TEST_CASE_WITH_PARAM(17, TCPropCacheDeferredRefreshTRUE, TI_IRowsetRefreshTRUE)
|
|
TEST_CASE_WITH_PARAM(18, TCPropUpdateRefreshTRUE, TI_IRowsetRefreshTRUE)
|
|
TEST_CASE_WITH_PARAM(19, TCZombieRefreshTRUE, TI_IRowsetRefreshTRUE)
|
|
TEST_CASE_WITH_PARAM(20, TCExtendedErrorsRefreshTRUE, TI_IRowsetRefreshTRUE)
|
|
TEST_CASE_WITH_PARAM(21, TCPropRefreshOnlyRefreshTRUE, TI_IRowsetRefreshTRUE)
|
|
TEST_CASE_WITH_PARAM(22, TCPropCanHoldRowsRefreshTRUEBLOBS, TI_IRowsetRefreshTRUE)
|
|
TEST_CASE_WITH_PARAM(23, TCNullRowRefreshTRUE, TI_IRowsetRefreshTRUE)
|
|
TEST_CASE_WITH_PARAM(24, TCMiscRefreshTRUE, TI_IRowsetRefreshTRUE)
|
|
//
|
|
TEST_CASE_WITH_PARAM(25, TCPropCanHoldRowsRefreshFALSE, TI_IRowsetRefreshFALSE)
|
|
TEST_CASE_WITH_PARAM(26, TCPropNoHoldRowsRefreshFALSE, TI_IRowsetRefreshFALSE)
|
|
TEST_CASE_WITH_PARAM(27, TCPropBookmarksRefreshFALSE, TI_IRowsetRefreshFALSE)
|
|
TEST_CASE_WITH_PARAM(28, TCPropDeferredRefreshFALSE, TI_IRowsetRefreshFALSE)
|
|
TEST_CASE_WITH_PARAM(29, TCPropUpdateRefreshFALSE, TI_IRowsetRefreshFALSE)
|
|
TEST_CASE_WITH_PARAM(30, TCPropCacheDeferredRefreshFALSE, TI_IRowsetRefreshFALSE)
|
|
TEST_CASE_WITH_PARAM(31, TCZombieRefreshFALSE, TI_IRowsetRefreshFALSE)
|
|
TEST_CASE_WITH_PARAM(32, TCExtendedErrorsRefreshFALSE, TI_IRowsetRefreshFALSE)
|
|
TEST_CASE_WITH_PARAM(33, TCPropRefreshOnlyRefreshFALSE, TI_IRowsetRefreshFALSE)
|
|
TEST_CASE_WITH_PARAM(34, TCPropCanHoldRowsRefreshFALSEBLOBS, TI_IRowsetRefreshFALSE)
|
|
TEST_CASE_WITH_PARAM(35, TCNullRowRefreshFALSE, TI_IRowsetRefreshFALSE)
|
|
TEST_CASE_WITH_PARAM(36, TCMiscRefreshFALSE, TI_IRowsetRefreshFALSE)
|
|
END_TEST_MODULE()
|
|
#endif
|
|
|
|
|
|
// {{ TCW_TC_PROTOTYPE(TCPropCanHoldRowsResynch)
|
|
//*-----------------------------------------------------------------------
|
|
//| Test Case: TCPropCanHoldRowsResynch - General Scenarios with CANHOLDROWS
|
|
//| Created: 05/28/96
|
|
//*-----------------------------------------------------------------------
|
|
|
|
//--------------------------------------------------------------------
|
|
// @mfunc TestCase Initialization Routine
|
|
//
|
|
// @rdesc TRUE or FALSE
|
|
//
|
|
BOOL TCPropCanHoldRowsResynch::Init()
|
|
{
|
|
if (TEST_SKIPPED==fnInterfaceSupported())
|
|
{
|
|
return TEST_SKIPPED;
|
|
}
|
|
|
|
// {{ TCW_INIT_BASECLASS_CHECK
|
|
if(CPropCanHoldRowsResynch::Init(m_eTI))
|
|
// }}
|
|
{
|
|
//Find highest isolation level
|
|
if (m_fSerializable)
|
|
{
|
|
m_fHighestSupportedIsoLevel = ISOLATIONLEVEL_SERIALIZABLE;
|
|
}
|
|
else
|
|
{
|
|
if (m_fRepeatableRead)
|
|
{
|
|
m_fHighestSupportedIsoLevel = ISOLATIONLEVEL_REPEATABLEREAD;
|
|
}
|
|
else
|
|
{
|
|
if (m_fReadCommitted)
|
|
{
|
|
m_fHighestSupportedIsoLevel = ISOLATIONLEVEL_READCOMMITTED;
|
|
}
|
|
else
|
|
{
|
|
if (m_fReadUncommitted)
|
|
{
|
|
m_fHighestSupportedIsoLevel = ISOLATIONLEVEL_READUNCOMMITTED;
|
|
}
|
|
else
|
|
{
|
|
m_fHighestSupportedIsoLevel = ISOLATIONLEVEL_CHAOS;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(1)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc Isolation Level - Chaos
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCPropCanHoldRowsResynch::Variation_1()
|
|
{
|
|
BOOL fResults = FALSE;
|
|
|
|
//If no provider support for this isolation level, just return pass
|
|
if (!m_fChaos)
|
|
{
|
|
odtLog << wszNoProviderSupport << L"CHAOS" << wszNewLine;
|
|
return TEST_PASS;
|
|
}
|
|
|
|
//Not all drivers allow starting a txn with rowsets
|
|
//open, so release them before starting a txn
|
|
ReleaseResynchObjects();
|
|
|
|
//Start txn we're testing at Chaos Isolation Level
|
|
if (CHECK(m_pRORowset1->m_pITxnLocal->StartTransaction(ISOLATIONLEVEL_CHAOS, 0, NULL, NULL), S_OK))
|
|
{
|
|
if (CreateResynchObjects(m_eTI))
|
|
{
|
|
if (GenerateResynchData(m_pRORowset1, ISOLATIONLEVEL_CHAOS, m_hROAccessor))
|
|
{
|
|
if (VerifyData(VERIFY_NEW,VERIFY_NEW,VERIFY_OLD,VERIFY_NEW))
|
|
{
|
|
//Everything went OK
|
|
fResults = TRUE;
|
|
}
|
|
FreeOutParams();
|
|
}
|
|
}
|
|
}
|
|
COMPARE(EndTxns(), TRUE);
|
|
|
|
if (fResults)
|
|
return TEST_PASS;
|
|
else
|
|
return TEST_FAIL;
|
|
}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(2)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc Isolation Level - Read Uncommitted
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCPropCanHoldRowsResynch::Variation_2()
|
|
{
|
|
BOOL fResults = FALSE;
|
|
|
|
//If no provider support for this isolation level, just return pass
|
|
if (!m_fReadUncommitted)
|
|
{
|
|
odtLog << wszNoProviderSupport << L"READUNCOMMITTED" << wszNewLine;
|
|
return TEST_PASS;
|
|
}
|
|
|
|
//Not all drivers allow starting a txn with rowsets
|
|
//open, so release them before starting a txn
|
|
ReleaseResynchObjects();
|
|
|
|
//Start txn we're testing at Read Uncommitted Isolation Level
|
|
if (CHECK(m_pRORowset1->m_pITxnLocal->StartTransaction(ISOLATIONLEVEL_READUNCOMMITTED, 0, NULL, NULL), S_OK))
|
|
{
|
|
if (CreateResynchObjects(m_eTI))
|
|
{
|
|
//Now do the same thing on our read only rowset
|
|
if (GenerateResynchData(m_pRORowset1, ISOLATIONLEVEL_READUNCOMMITTED,m_hROAccessor))
|
|
{
|
|
if (VerifyData(VERIFY_NEW,VERIFY_NEW,VERIFY_OLD,VERIFY_NEW))
|
|
{
|
|
//Everything went OK
|
|
fResults = TRUE;
|
|
}
|
|
FreeOutParams();
|
|
}
|
|
}
|
|
COMPARE(EndTxns(), TRUE);
|
|
}
|
|
if (fResults)
|
|
return TEST_PASS;
|
|
else
|
|
return TEST_FAIL;
|
|
}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(3)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc Isolation Level - Read Committed
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCPropCanHoldRowsResynch::Variation_3()
|
|
{
|
|
BOOL fResults = FALSE;
|
|
|
|
//If no provider support for this isolation level, just return pass
|
|
if (!m_fReadCommitted)
|
|
{
|
|
odtLog << wszNoProviderSupport << L"READCOMMITTED" << wszNewLine;
|
|
return TEST_PASS;
|
|
}
|
|
|
|
//Not all drivers allow starting a txn with rowsets
|
|
//open, so release them before starting a txn
|
|
ReleaseResynchObjects();
|
|
|
|
//Start txn we're testing at Read Committed Isolation Level
|
|
if (CHECK(StartTxns(ISOLATIONLEVEL_READCOMMITTED), S_OK))
|
|
{
|
|
if (CreateResynchObjects(m_eTI))
|
|
{
|
|
//Test visible data on our changeable rowset
|
|
if (GenerateResynchData(m_pChgRowset1, ISOLATIONLEVEL_READCOMMITTED, m_hChgAccessor))
|
|
{
|
|
if (VerifyData(VERIFY_NEW,VERIFY_NEW,VERIFY_OLD,VERIFY_NEW))
|
|
{
|
|
//Now do the same thing on our read only rowset
|
|
if (GenerateResynchData(m_pRORowset1, ISOLATIONLEVEL_READCOMMITTED, m_hROAccessor))
|
|
{
|
|
if (VerifyData(VERIFY_NEW,VERIFY_NEW,VERIFY_OLD,VERIFY_NEW))
|
|
{
|
|
//Everything went OK
|
|
fResults = TRUE;
|
|
FreeOutParams();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
COMPARE(EndTxns(), TRUE);
|
|
}
|
|
if (fResults)
|
|
return TEST_PASS;
|
|
else
|
|
return TEST_FAIL;
|
|
}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(4)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc Isolation Level - Repeatable Read
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCPropCanHoldRowsResynch::Variation_4()
|
|
{
|
|
BOOL fResults = FALSE;
|
|
|
|
//If no provider support for this isolation level, just return pass
|
|
if (!m_fRepeatableRead)
|
|
{
|
|
odtLog << wszNoProviderSupport << L"REPEATABLEREAD" << wszNewLine;
|
|
return TEST_PASS;
|
|
}
|
|
|
|
//Not all drivers allow starting a txn with rowsets
|
|
//open, so release them before starting a txn
|
|
ReleaseResynchObjects();
|
|
|
|
//Start txn we're testing at Read Repeated Isolation Level
|
|
if (CHECK(StartTxns(ISOLATIONLEVEL_REPEATABLEREAD), S_OK))
|
|
{
|
|
if (CreateResynchObjects(m_eTI))
|
|
{
|
|
//Test visible data on our changeable rowset
|
|
if (GenerateResynchData(m_pChgRowset1, ISOLATIONLEVEL_REPEATABLEREAD, m_hChgAccessor))
|
|
{
|
|
if (VerifyData(VERIFY_OLD, VERIFY_OLD, VERIFY_OLD, VERIFY_OLD))
|
|
{
|
|
//Now do the same thing on our read only rowset
|
|
if (GenerateResynchData(m_pRORowset1, ISOLATIONLEVEL_REPEATABLEREAD, m_hROAccessor))
|
|
{
|
|
if (VerifyData(VERIFY_OLD, VERIFY_OLD, VERIFY_OLD, VERIFY_OLD))
|
|
{
|
|
//Everything went OK
|
|
fResults = TRUE;
|
|
}
|
|
}
|
|
}
|
|
FreeOutParams();
|
|
}
|
|
}
|
|
EndTxns();
|
|
}
|
|
if (fResults)
|
|
return TEST_PASS;
|
|
else
|
|
return TEST_FAIL;
|
|
}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(5)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc Isolation Level - Serializable
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCPropCanHoldRowsResynch::Variation_5()
|
|
{
|
|
BOOL fResults = FALSE;
|
|
|
|
//If no provider support for this isolation level, just return pass
|
|
if (!m_fSerializable)
|
|
{
|
|
odtLog << wszNoProviderSupport << L"SERIALIZABLE" << wszNewLine;
|
|
return TEST_PASS;
|
|
}
|
|
|
|
//Not all drivers allow starting a txn with rowsets
|
|
//open, so release them before starting a txn
|
|
ReleaseResynchObjects();
|
|
|
|
//Start txn we're testing at Serializable Isolation Level
|
|
if (CHECK(StartTxns(ISOLATIONLEVEL_SERIALIZABLE), S_OK))
|
|
{
|
|
if (CreateResynchObjects(m_eTI))
|
|
{
|
|
//Test visible data on our changeable rowset
|
|
if (GenerateResynchData(m_pChgRowset1, ISOLATIONLEVEL_SERIALIZABLE, m_hChgAccessor))
|
|
{
|
|
if (VerifyData(VERIFY_OLD, VERIFY_OLD, VERIFY_OLD, VERIFY_OLD))
|
|
{
|
|
//Now do the same thing on our read only rowset
|
|
if (GenerateResynchData(m_pRORowset1, ISOLATIONLEVEL_SERIALIZABLE, m_hROAccessor))
|
|
{
|
|
if (VerifyData(VERIFY_OLD, VERIFY_OLD, VERIFY_OLD, VERIFY_OLD))
|
|
{
|
|
//Everything went OK
|
|
fResults = TRUE;
|
|
}
|
|
}
|
|
}
|
|
FreeOutParams();
|
|
}
|
|
}
|
|
COMPARE(EndTxns(), TRUE);
|
|
}
|
|
if (fResults)
|
|
return TEST_PASS;
|
|
else
|
|
return TEST_FAIL;
|
|
}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(6)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc Isolation Level - Unspecified
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCPropCanHoldRowsResynch::Variation_6()
|
|
{
|
|
BOOL fResults = FALSE;
|
|
|
|
//Start txn we're testing at unspecified Isolation Level
|
|
if (CHECK(StartTxns(ISOLATIONLEVEL_UNSPECIFIED), XACT_E_ISOLATIONLEVEL))
|
|
{
|
|
//Everything went OK
|
|
fResults = TRUE;
|
|
}
|
|
|
|
//in case a txn was started
|
|
COMPARE(EndTxns(), TRUE);
|
|
|
|
if (fResults)
|
|
return TEST_PASS;
|
|
else
|
|
return TEST_FAIL;
|
|
}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(7)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc Own Insert - Highest Isolation Level
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCPropCanHoldRowsResynch::Variation_7()
|
|
{
|
|
BOOL fResults = FALSE;
|
|
HROW hRow = DB_NULL_HROW;
|
|
ULONG cRowsObtained = 0;
|
|
HRESULT ExpectedHr;
|
|
BOOL fOverWrite = TRUE;
|
|
|
|
if (m_eTI==TI_IRowsetRefreshFALSE)
|
|
{
|
|
fOverWrite=FALSE;
|
|
}
|
|
|
|
//If no provider support for this isolation level, just return pass
|
|
if (!m_fChaos && !m_fReadUncommitted && !m_fReadCommitted &&
|
|
!m_fRepeatableRead && !m_fSerializable)
|
|
{
|
|
odtLog << wszNoProviderSupport << L"ANY" << wszNewLine;
|
|
return TEST_PASS;
|
|
}
|
|
|
|
//Not all drivers allow starting a txn with rowsets
|
|
//open, so release them before starting a txn
|
|
ReleaseResynchObjects();
|
|
|
|
//Set the highest possible isolation level, to make this test interesting
|
|
//since regardless of isolation, we should always see our own insert.
|
|
//Note that we only start a txn for this rowset and not the RORowset,
|
|
//since otherwise the RORowset could lock us from inserting
|
|
//due to the high isolation level
|
|
if (!CHECK(m_pChgRowset1->m_pITxnLocal->StartTransaction(m_fHighestSupportedIsoLevel, 0, NULL, NULL), S_OK))
|
|
goto CLEANUP;
|
|
|
|
if (!COMPARE(CreateResynchObjects(m_eTI), TRUE))
|
|
goto CLEANUP;
|
|
|
|
//Insert new row ourselves and keep hRow
|
|
if (!COMPARE(m_pChgRowset1->Insert(GetNextRowToInsert(), &hRow), TRUE))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
//increment for comparasion
|
|
g_ulLastActualInsert++;
|
|
|
|
//If we don't support strong identity, our single row will fail
|
|
if (m_fStrongIdentity)
|
|
{
|
|
ExpectedHr = S_OK;
|
|
}
|
|
else
|
|
{
|
|
ExpectedHr = DB_E_ERRORSOCCURRED;
|
|
}
|
|
|
|
//flag to see if RefreshVisibleRows has been called
|
|
m_cRowsResynched = 5;
|
|
m_rghRowsResynched = (HROW *)JUNK_PTR;
|
|
m_rgRowStatus = (DBROWSTATUS *)JUNK_PTR;
|
|
|
|
//Now do a ResynchRows to see if inserted row data is brought in
|
|
if (!CHECK(ResynchRefresh(DB_NULL_HCHAPTER,1, &hRow, fOverWrite, &m_cRowsResynched, &m_rghRowsResynched, &m_rgRowStatus, FALSE), ExpectedHr))
|
|
{
|
|
FreeOutParams();
|
|
goto CLEANUP;
|
|
}
|
|
|
|
//don't check the rowstatus here. depending on if the row has defualts there might be some refreshing going on
|
|
|
|
//This only applies if we support resynch on this newly inserted row
|
|
if (m_fStrongIdentity)
|
|
{
|
|
//Now Get Newly Resynch'd Data
|
|
if (!CHECK(m_pChgIRowset->GetData(hRow, m_hChgAccessor, m_pResynchRowsetData), S_OK))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
//Now GetVisibleData on the same row
|
|
if (!CHECK(GetLastVisibleData(hRow, m_hChgAccessor, m_pResynchVisibleData,FALSE), S_OK))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
|
|
//refresh should bring in the defaults
|
|
|
|
//Now make sure we could see the new data at all times, since its our own insert
|
|
if (VerifyData(VERIFY_NEW, VERIFY_IGNORE, VERIFY_IGNORE, VERIFY_NEW))
|
|
{
|
|
//Everything went OK
|
|
fResults = TRUE;
|
|
}
|
|
}
|
|
//Make sure our status is right
|
|
else
|
|
{
|
|
COMPARE(m_cRowsResynched,1);
|
|
COMPARE(m_rghRowsResynched[0],hRow);
|
|
CompareOutParams(1, &hRow);
|
|
fResults = COMPARE(m_rgRowStatus[0], DBROWSTATUS_E_NEWLYINSERTED);
|
|
}
|
|
|
|
fResults = TRUE;
|
|
CLEANUP:
|
|
if (5!=m_cRowsResynched)
|
|
{
|
|
FreeOutParams();
|
|
}
|
|
if (hRow != DB_NULL_HROW)
|
|
m_pChgIRowset->ReleaseRows(1, &hRow, NULL, NULL, NULL);
|
|
|
|
//back out changes
|
|
COMPARE(EndTxns(TRUE), TRUE);
|
|
g_ulLastActualInsert--;
|
|
|
|
if (fResults)
|
|
return TEST_PASS;
|
|
else
|
|
return TEST_FAIL;
|
|
}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(8)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc Variable Length Columns Only Bound
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCPropCanHoldRowsResynch::Variation_8()
|
|
{
|
|
BOOL fResults = FALSE;
|
|
HACCESSOR hChgAccessor = DB_NULL_HACCESSOR;
|
|
HACCESSOR hROAccessor = DB_NULL_HACCESSOR;
|
|
DBBINDING *rgBindings = NULL;
|
|
DBCOUNTITEM cBindings = 0;
|
|
|
|
ReleaseResynchObjects();
|
|
if (!COMPARE(CreateResynchObjects(m_eTI), TRUE))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
//Get accessors with only variable length bound. Bindings will be the same
|
|
//for changeable and read only rowsets
|
|
if (!CHECK(GetAccessorAndBindings(m_pChgRowset1->m_pIAccessor, DBACCESSOR_ROWDATA,
|
|
&hChgAccessor, &rgBindings, &cBindings, NULL,
|
|
DBPART_VALUE | DBPART_LENGTH | DBPART_STATUS,
|
|
VARIABLE_LEN_COLS_BOUND,
|
|
FORWARD, NO_COLS_BY_REF, NULL, NULL,
|
|
NULL, DBTYPE_EMPTY, 0, NULL, NULL,
|
|
NO_COLS_OWNED_BY_PROV, DBPARAMIO_NOTPARAM,
|
|
m_fBindLongData),S_OK))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
if (!CHECK(GetAccessorAndBindings(m_pRORowset1->m_pIAccessor, DBACCESSOR_ROWDATA,
|
|
&hROAccessor, NULL, NULL, NULL,
|
|
DBPART_VALUE | DBPART_LENGTH | DBPART_STATUS,
|
|
VARIABLE_LEN_COLS_BOUND,
|
|
FORWARD, NO_COLS_BY_REF, NULL, NULL,
|
|
NULL, DBTYPE_EMPTY, 0, NULL, NULL,
|
|
NO_COLS_OWNED_BY_PROV, DBPARAMIO_NOTPARAM,
|
|
m_fBindLongData),S_OK))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
//Test visible data on our changeable rowset
|
|
if (GenerateResynchData(m_pChgRowset1, ISOLATIONLEVEL_CHAOS, hChgAccessor, rgBindings, cBindings))
|
|
{
|
|
if (VerifyData(VERIFY_NEW, VERIFY_NEW, VERIFY_OLD, VERIFY_NEW, 0, 0, cBindings, rgBindings))
|
|
{
|
|
//Now do the same thing on our read only rowset
|
|
if (GenerateResynchData(m_pRORowset1, ISOLATIONLEVEL_CHAOS, hROAccessor, rgBindings, cBindings))
|
|
{
|
|
if (VerifyData(VERIFY_NEW, VERIFY_NEW, VERIFY_OLD, VERIFY_NEW, 0, 0, cBindings, rgBindings))
|
|
{
|
|
//Everything went OK
|
|
fResults = TRUE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
CLEANUP:
|
|
FreeOutParams();
|
|
if (hChgAccessor != DB_NULL_HACCESSOR)
|
|
m_pChgRowset1->m_pIAccessor->ReleaseAccessor(hChgAccessor, NULL);
|
|
|
|
if (hROAccessor != DB_NULL_HACCESSOR)
|
|
m_pRORowset1->m_pIAccessor->ReleaseAccessor(hROAccessor, NULL);
|
|
|
|
if (rgBindings)
|
|
PROVIDER_FREE(rgBindings);
|
|
|
|
if (fResults)
|
|
return TEST_PASS;
|
|
else
|
|
return TEST_FAIL;
|
|
}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(9)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc Fixed Length Columns Only Bound
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCPropCanHoldRowsResynch::Variation_9()
|
|
{
|
|
BOOL fResults = FALSE;
|
|
HACCESSOR hChgAccessor = DB_NULL_HACCESSOR;
|
|
HACCESSOR hROAccessor = DB_NULL_HACCESSOR;
|
|
DBBINDING *rgBindings = NULL;
|
|
DBCOUNTITEM cBindings = 0;
|
|
|
|
ReleaseResynchObjects();
|
|
if (!COMPARE(CreateResynchObjects(m_eTI), TRUE))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
//Get accessors with only variable length bound. Bindings will be the same
|
|
//for changeable and read only rowsets
|
|
|
|
//Get accessors with only fixed length bound, bindings
|
|
//are the same for changeable and RO accessors
|
|
if (!CHECK(GetAccessorAndBindings(m_pChgRowset1->m_pIAccessor, DBACCESSOR_ROWDATA,
|
|
&hChgAccessor, &rgBindings, &cBindings, NULL,
|
|
DBPART_VALUE | DBPART_LENGTH | DBPART_STATUS,
|
|
FIXED_LEN_COLS_BOUND,
|
|
FORWARD, NO_COLS_BY_REF, NULL, NULL,
|
|
NULL, DBTYPE_EMPTY, 0, NULL, NULL,
|
|
NO_COLS_OWNED_BY_PROV, DBPARAMIO_NOTPARAM,
|
|
m_fBindLongData),S_OK))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
//Test visible data on our changeable rowset
|
|
if (GenerateResynchData(m_pChgRowset1, ISOLATIONLEVEL_CHAOS, hChgAccessor, rgBindings, cBindings))
|
|
{
|
|
if (VerifyData(VERIFY_NEW, VERIFY_NEW, VERIFY_OLD, VERIFY_NEW, 0, 0, cBindings, rgBindings))
|
|
{
|
|
ReleaseResynchObjects();
|
|
if (!COMPARE(CreateResynchObjects(m_eTI), TRUE))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
if (!CHECK(GetAccessorAndBindings(m_pRORowset1->m_pIAccessor, DBACCESSOR_ROWDATA,
|
|
&hROAccessor, NULL, NULL, NULL,
|
|
DBPART_VALUE | DBPART_LENGTH | DBPART_STATUS,
|
|
FIXED_LEN_COLS_BOUND,
|
|
FORWARD, NO_COLS_BY_REF, NULL, NULL,
|
|
NULL, DBTYPE_EMPTY, 0, NULL, NULL,
|
|
NO_COLS_OWNED_BY_PROV, DBPARAMIO_NOTPARAM,
|
|
m_fBindLongData),S_OK))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
//Now do the same thing on our read only rowset
|
|
if (GenerateResynchData(m_pRORowset1, ISOLATIONLEVEL_CHAOS, hROAccessor, rgBindings, cBindings))
|
|
{
|
|
if (VerifyData(VERIFY_NEW, VERIFY_NEW, VERIFY_OLD, VERIFY_NEW, 0, 0, cBindings, rgBindings))
|
|
{
|
|
//Everything went OK
|
|
fResults = TRUE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
CLEANUP:
|
|
FreeOutParams();
|
|
if (rgBindings)
|
|
PROVIDER_FREE(rgBindings);
|
|
|
|
if (hChgAccessor != DB_NULL_HACCESSOR)
|
|
m_pChgRowset1->m_pIAccessor->ReleaseAccessor(hChgAccessor, NULL);
|
|
if (hROAccessor != DB_NULL_HACCESSOR)
|
|
m_pRORowset1->m_pIAccessor->ReleaseAccessor(hROAccessor, NULL);
|
|
|
|
if (fResults)
|
|
return TEST_PASS;
|
|
else
|
|
return TEST_FAIL;
|
|
}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(10)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc All Columns Bound BYREF
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCPropCanHoldRowsResynch::Variation_10()
|
|
{
|
|
BOOL fResults = FALSE;
|
|
HACCESSOR hChgAccessor = DB_NULL_HACCESSOR;
|
|
HACCESSOR hROAccessor = DB_NULL_HACCESSOR;
|
|
ULONG i = 0;
|
|
DBBINDING *rgBindings = NULL;
|
|
DBCOUNTITEM cBindings = 0;
|
|
DBLENGTH cRowSize = 0;
|
|
|
|
//Test visible data on our changeable rowset, repeat it several times
|
|
//to flush out any potential memory leaks and stress test it
|
|
for (i = 0; i< STRESS_RESYNCH_REPS; i++)
|
|
{
|
|
ReleaseResynchObjects();
|
|
if (!COMPARE(CreateResynchObjects(m_eTI), TRUE))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
//Since some provider's only support variable length
|
|
//cols by ref, limit the accessor to these
|
|
if (!CHECK(GetAccessorAndBindings(m_pChgRowset1->m_pIAccessor,
|
|
DBACCESSOR_ROWDATA,
|
|
&hChgAccessor, &rgBindings, &cBindings, &cRowSize,
|
|
DBPART_LENGTH | DBPART_STATUS | DBPART_VALUE,
|
|
ALL_COLS_BOUND, FORWARD, VARIABLE_LEN_COLS_BY_REF,
|
|
NULL, NULL,
|
|
NULL, DBTYPE_EMPTY, 0, NULL, NULL,
|
|
NO_COLS_OWNED_BY_PROV, DBPARAMIO_NOTPARAM,
|
|
m_fBindLongData),S_OK))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
//re-create buffers with the new accesor and bindings created just above
|
|
FreeBuffers(m_cbRowSize);
|
|
AllocDataBuffers(cRowSize);
|
|
|
|
if (GenerateResynchData(m_pChgRowset1, ISOLATIONLEVEL_CHAOS, hChgAccessor, rgBindings, cBindings))
|
|
{
|
|
if (VerifyData(VERIFY_NEW, VERIFY_NEW, VERIFY_OLD, VERIFY_NEW, 0, 0, cBindings, rgBindings))
|
|
{
|
|
//re-re-create buffers so class functions work correctly. yes, kind of hokey.
|
|
//free with Compare to take a care of byref value
|
|
CompareData( m_pChgRowset1->m_pTable->CountColumnsOnTable(), m_pChgRowset1->m_rgTableColOrds, 1,
|
|
m_pVisibleData, cBindings, rgBindings,
|
|
m_pChgRowset1->m_pTable, m_pIMalloc, PRIMARY,
|
|
FREE_ONLY
|
|
);
|
|
CompareData( m_pChgRowset1->m_pTable->CountColumnsOnTable(), m_pChgRowset1->m_rgTableColOrds, 1,
|
|
m_pRowsetData, cBindings, rgBindings,
|
|
m_pChgRowset1->m_pTable, m_pIMalloc, PRIMARY,
|
|
FREE_ONLY
|
|
);
|
|
CompareData( m_pChgRowset1->m_pTable->CountColumnsOnTable(), m_pChgRowset1->m_rgTableColOrds, 1,
|
|
m_pResynchRowsetData, cBindings, rgBindings,
|
|
m_pChgRowset1->m_pTable, m_pIMalloc, PRIMARY,
|
|
FREE_ONLY
|
|
);
|
|
CompareData( m_pChgRowset1->m_pTable->CountColumnsOnTable(), m_pChgRowset1->m_rgTableColOrds, 1,
|
|
m_pResynchVisibleData, cBindings, rgBindings,
|
|
m_pChgRowset1->m_pTable, m_pIMalloc, PRIMARY,
|
|
FREE_ONLY
|
|
);
|
|
|
|
/* FreeBuffers(cRowSize);
|
|
AllocDataBuffers(m_cbRowSize);
|
|
ReleaseResynchObjects();
|
|
if (!COMPARE(CreateResynchObjects(m_eTI), TRUE))
|
|
{
|
|
FreeOutParams();
|
|
goto CLEANUP;
|
|
}*/
|
|
if (!CHECK(GetAccessorAndBindings( m_pRORowset1->m_pIAccessor,
|
|
DBACCESSOR_ROWDATA,
|
|
&hROAccessor, NULL, NULL, NULL,
|
|
DBPART_LENGTH | DBPART_STATUS | DBPART_VALUE,
|
|
ALL_COLS_BOUND, FORWARD, VARIABLE_LEN_COLS_BY_REF,
|
|
NULL, NULL,
|
|
NULL, DBTYPE_EMPTY, 0, NULL, NULL,
|
|
NO_COLS_OWNED_BY_PROV, DBPARAMIO_NOTPARAM,
|
|
m_fBindLongData),S_OK))
|
|
{
|
|
FreeOutParams();
|
|
goto CLEANUP;
|
|
}
|
|
/* //re-create buffers with the new accesor and bindings created just above
|
|
FreeBuffers(m_cbRowSize);
|
|
AllocDataBuffers(cRowSize);
|
|
*/
|
|
//Now do the same thing on our read only rowset
|
|
if (GenerateResynchData(m_pRORowset1, ISOLATIONLEVEL_CHAOS, hROAccessor, rgBindings, cBindings))
|
|
{
|
|
if (VerifyData(VERIFY_NEW, VERIFY_NEW, VERIFY_OLD, VERIFY_NEW, 0, 0, cBindings, rgBindings))
|
|
{
|
|
//Everything went OK
|
|
fResults = TRUE;
|
|
//re-re-create buffers so class functoins work correctly. yes, kind of hokey
|
|
//free with Compare to take a care of byref value
|
|
CompareData( m_pChgRowset1->m_pTable->CountColumnsOnTable(), m_pChgRowset1->m_rgTableColOrds, 1,
|
|
m_pVisibleData, cBindings, rgBindings,
|
|
m_pChgRowset1->m_pTable, m_pIMalloc, PRIMARY,
|
|
FREE_ONLY
|
|
);
|
|
CompareData( m_pChgRowset1->m_pTable->CountColumnsOnTable(), m_pChgRowset1->m_rgTableColOrds, 1,
|
|
m_pRowsetData, cBindings, rgBindings,
|
|
m_pChgRowset1->m_pTable, m_pIMalloc, PRIMARY,
|
|
FREE_ONLY
|
|
);
|
|
CompareData( m_pChgRowset1->m_pTable->CountColumnsOnTable(), m_pChgRowset1->m_rgTableColOrds, 1,
|
|
m_pResynchRowsetData, cBindings, rgBindings,
|
|
m_pChgRowset1->m_pTable, m_pIMalloc, PRIMARY,
|
|
FREE_ONLY
|
|
);
|
|
CompareData( m_pChgRowset1->m_pTable->CountColumnsOnTable(), m_pChgRowset1->m_rgTableColOrds, 1,
|
|
m_pResynchVisibleData, cBindings, rgBindings,
|
|
m_pChgRowset1->m_pTable, m_pIMalloc, PRIMARY,
|
|
FREE_ONLY
|
|
);
|
|
|
|
FreeBuffers(cRowSize);
|
|
AllocDataBuffers(m_cbRowSize);
|
|
//free mem each time through the loop
|
|
FreeAccessorBindings(cBindings,rgBindings);
|
|
rgBindings = NULL;
|
|
if (hChgAccessor != DB_NULL_HACCESSOR)
|
|
{
|
|
m_pChgRowset1->m_pIAccessor->ReleaseAccessor(hChgAccessor, NULL);
|
|
}
|
|
if (hROAccessor != DB_NULL_HACCESSOR)
|
|
{
|
|
m_pRORowset1->m_pIAccessor->ReleaseAccessor(hROAccessor, NULL);
|
|
}
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
//If we broke before we finished loop, there was an error
|
|
if (i != STRESS_RESYNCH_REPS)
|
|
{
|
|
fResults = FALSE;
|
|
}
|
|
CLEANUP:
|
|
ReleaseResynchObjects();
|
|
FreeOutParams();
|
|
|
|
if (rgBindings)
|
|
{
|
|
FreeAccessorBindings(cBindings,rgBindings);
|
|
rgBindings = NULL;
|
|
if (hChgAccessor != DB_NULL_HACCESSOR && m_pChgRowset1->m_pIAccessor)
|
|
{
|
|
m_pChgRowset1->m_pIAccessor->ReleaseAccessor(hChgAccessor, NULL);
|
|
}
|
|
if (hROAccessor != DB_NULL_HACCESSOR && m_pRORowset1->m_pIAccessor)
|
|
{
|
|
m_pRORowset1->m_pIAccessor->ReleaseAccessor(hROAccessor, NULL);
|
|
}
|
|
}
|
|
if (fResults)
|
|
return TEST_PASS;
|
|
else
|
|
return TEST_FAIL;
|
|
}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(11)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc Own Update - Highest Isolation Level
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCPropCanHoldRowsResynch::Variation_11()
|
|
{
|
|
BOOL fResults = FALSE;
|
|
HROW hRow = DB_NULL_HROW;
|
|
ULONG cRowsObtained = 0;
|
|
HRESULT hr;
|
|
BOOL fOverWrite = TRUE;
|
|
|
|
if (m_eTI==TI_IRowsetRefreshFALSE)
|
|
{
|
|
fOverWrite=FALSE;
|
|
}
|
|
|
|
//If no provider support for this isolation level, just return pass
|
|
if (!m_fChaos && !m_fReadUncommitted && !m_fReadCommitted &&
|
|
!m_fRepeatableRead && !m_fSerializable)
|
|
{
|
|
odtLog << wszNoProviderSupport << L"ANY" << wszNewLine;
|
|
return TEST_PASS;
|
|
}
|
|
|
|
//Not all drivers allow starting a txn with rowsets
|
|
//open, so release them before starting a txn
|
|
ReleaseResynchObjects();
|
|
|
|
//Set the highest possible isolation level, to make this test interesting
|
|
//since regardless of isolation, we should always see our own change.
|
|
//Note that we only start a txn for this rowset and not the RORowset,
|
|
//since otherwise the RORowset could lock us from changing
|
|
//due to the high isolation level
|
|
if (!CHECK(m_pChgRowset1->m_pITxnLocal->StartTransaction(m_fHighestSupportedIsoLevel, 0, NULL, NULL), S_OK))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
if (!COMPARE(CreateResynchObjects(m_eTI), TRUE))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
//Change a row ourselves and keep hRow
|
|
if (!COMPARE(m_pChgRowset1->Change(GetNextRowToDelete(), GetNextRowToInsert(), &hRow), TRUE))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
//increment this for the comparision
|
|
g_ulLastActualInsert++;
|
|
|
|
//Next GetData from cache
|
|
if (!CHECK(m_pChgIRowset->GetData(hRow, m_hChgAccessor, m_pRowsetData), S_OK))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
//Now do a ResynchRows to see if new data is brought in
|
|
if (!CHECK(ResynchRefresh(DB_NULL_HCHAPTER,1, &hRow, fOverWrite,&m_cRowsResynched, &m_rghRowsResynched, &m_rgRowStatus,FALSE), S_OK))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
//Now Get Newly Resynch'd Data
|
|
if (!CHECK(m_pChgIRowset->GetData(hRow, m_hChgAccessor, m_pResynchRowsetData), S_OK))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
//Now GetVisibleData on the same row
|
|
hr=GetLastVisibleData(hRow, m_hChgAccessor, m_pResynchVisibleData,FALSE);
|
|
if (hr!=S_OK)
|
|
{
|
|
//account for the fact that some providers might delete/insert a row when asked to change it
|
|
//this may put a hole in the rowset and put the newrow somewhere else in the rowset (most likley at the end of the rowset)
|
|
if (DB_E_DELETEDROW==hr)
|
|
{
|
|
fResults = TRUE;
|
|
goto CLEANUP;
|
|
}
|
|
else
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
}
|
|
|
|
//no change is made, these should be the same
|
|
if(CompareBuffer(m_pResynchVisibleData,m_pResynchRowsetData,m_cBindings,m_rgBindings,m_pIMalloc,FALSE,FALSE,COMPARE_ONLY)!=TRUE)
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
|
|
//Now make sure we could see the new data at all times, since our own update
|
|
if (VerifyData(VERIFY_NEW, VERIFY_IGNORE, VERIFY_NEW, VERIFY_IGNORE))
|
|
{
|
|
//Everything went OK
|
|
fResults = TRUE;
|
|
}
|
|
CLEANUP:
|
|
FreeOutParams();
|
|
|
|
//abort the change, easier to manage the test this way
|
|
COMPARE(EndTxns(TRUE), TRUE);
|
|
g_ulLastActualInsert--;
|
|
|
|
if (hRow != DB_NULL_HROW)
|
|
m_pChgIRowset->ReleaseRows(1, &hRow, NULL, NULL, NULL);
|
|
|
|
if (fResults)
|
|
return TEST_PASS;
|
|
else
|
|
return TEST_FAIL;
|
|
}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(12)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc GetVisibleData with PASSBYREF - DB_E_BADACCESSORHANDLE
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCPropCanHoldRowsResynch::Variation_12()
|
|
{
|
|
HACCESSOR hChgAccessor = DB_NULL_HACCESSOR;
|
|
BOOL fResults = FALSE;
|
|
HROW hRow = DB_NULL_HROW;
|
|
|
|
ReleaseResynchObjects();
|
|
if (!COMPARE(CreateResynchObjects(m_eTI), TRUE))
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
//We will skip this variation is provider doesn't support PASSBYREF
|
|
if (!m_fPassByRef)
|
|
{
|
|
odtLog << L"This Provider doesn't support PASSBYREF accessors. Variation is not applicable.\n";
|
|
return TEST_PASS;
|
|
}
|
|
|
|
//Get a PASSBYREF accessor
|
|
if (CHECK(m_pChgRowset1->m_pIAccessor->CreateAccessor(
|
|
DBACCESSOR_ROWDATA | DBACCESSOR_PASSBYREF, m_cBindings,
|
|
m_rgBindings, m_cbRowSize, &hChgAccessor, NULL), S_OK))
|
|
{
|
|
//Get an hRow
|
|
if (COMPARE(m_pChgRowset1->FindRow(GetNextRowToDelete(), &hRow), TRUE))
|
|
{
|
|
//Any pass by ref accessor should fail
|
|
if (CHECK(GetLastVisibleData(hRow, hChgAccessor, m_pVisibleData,FALSE), DB_E_BADACCESSORHANDLE))
|
|
{
|
|
fResults = TRUE;
|
|
}
|
|
//Now clean up our row handle
|
|
m_pChgIRowset->ReleaseRows(1, &hRow, NULL, NULL, NULL);
|
|
}
|
|
|
|
m_pChgRowset1->m_pIAccessor->ReleaseAccessor(hChgAccessor, NULL);
|
|
}
|
|
|
|
if (fResults)
|
|
return TEST_PASS;
|
|
else
|
|
return TEST_FAIL;
|
|
}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(13)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc GetVisibleData with PROVIDEROWNED - DB_E_BADACCESSORHANDLE
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCPropCanHoldRowsResynch::Variation_13()
|
|
{
|
|
HACCESSOR hChgAccessor = DB_NULL_HACCESSOR;
|
|
BOOL fResults = FALSE;
|
|
HROW hRow = DB_NULL_HROW;
|
|
DBBINDING *rgBindings = NULL;
|
|
DBCOUNTITEM cBindings;
|
|
DBLENGTH cbRowSize;
|
|
|
|
ReleaseResynchObjects();
|
|
if (!COMPARE(CreateResynchObjects(m_eTI), TRUE))
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
//Get bindings for a by ref accessor, use variable len only cols
|
|
if (CHECK(GetAccessorAndBindings(m_pChgRowset1->m_pIAccessor, DBACCESSOR_ROWDATA,
|
|
&hChgAccessor, &rgBindings, &cBindings, &cbRowSize,
|
|
DBPART_VALUE | DBPART_LENGTH | DBPART_STATUS,
|
|
VARIABLE_LEN_COLS_BOUND, FORWARD, ALL_COLS_BY_REF,
|
|
NULL, NULL,
|
|
NULL, DBTYPE_EMPTY, 0, NULL, NULL,
|
|
NO_COLS_OWNED_BY_PROV, DBPARAMIO_NOTPARAM,
|
|
m_fBindLongData),S_OK))
|
|
{
|
|
//We only wanted bindings
|
|
CHECK(m_pChgRowset1->m_pIAccessor->ReleaseAccessor(hChgAccessor, NULL), S_OK);
|
|
hChgAccessor = DB_NULL_HACCESSOR;
|
|
|
|
//We know this is a variable length column by ref, so provider owned
|
|
//should be fine here under normal GetData situations
|
|
rgBindings[0].dwMemOwner = DBMEMOWNER_PROVIDEROWNED;
|
|
|
|
//Now create the accessor which has provider owned memory
|
|
if (CHECK(m_pChgRowset1->m_pIAccessor->CreateAccessor(
|
|
DBACCESSOR_ROWDATA, cBindings,
|
|
rgBindings, cbRowSize,
|
|
&hChgAccessor, NULL), S_OK))
|
|
{
|
|
//Get an hRow
|
|
if (COMPARE(m_pChgRowset1->FindRow(GetNextRowToDelete(), &hRow), TRUE))
|
|
{
|
|
//Now try with the provider owned memory binding to GetVisibleData
|
|
//This will either succeed or return an error if not supported
|
|
m_hr = GetLastVisibleData(hRow, hChgAccessor, m_pVisibleData,FALSE);
|
|
if (m_hr != S_OK)
|
|
{
|
|
CHECK(m_hr, DB_E_BADACCESSORHANDLE);
|
|
}
|
|
|
|
fResults = TRUE;
|
|
|
|
//Now clean up our row handle
|
|
m_pChgIRowset->ReleaseRows(1, &hRow, NULL, NULL, NULL);
|
|
}
|
|
|
|
m_pChgRowset1->m_pIAccessor->ReleaseAccessor(hChgAccessor, NULL);
|
|
}
|
|
|
|
PROVIDER_FREE(rgBindings);
|
|
}
|
|
|
|
if (fResults)
|
|
return TEST_PASS;
|
|
else
|
|
return TEST_FAIL;
|
|
}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(14)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc ResynchRows/RefreshVisibleData with hRow = DB_NULL_HROW - DB_E_BADROWHANDLE
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCPropCanHoldRowsResynch::Variation_14()
|
|
{
|
|
HROW hRow = DB_NULL_HROW;
|
|
BOOL fOverWrite = TRUE;
|
|
|
|
if (m_eTI==TI_IRowsetRefreshFALSE)
|
|
{
|
|
fOverWrite=FALSE;
|
|
}
|
|
|
|
ReleaseResynchObjects();
|
|
if (!COMPARE(CreateResynchObjects(m_eTI), TRUE))
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
//Note, provider not required to check for this return code
|
|
if (CHECK(GetLastVisibleData(hRow, m_hChgAccessor, m_pVisibleData,FALSE), DB_E_BADROWHANDLE))
|
|
{
|
|
m_cRowsResynched = 5;
|
|
m_rghRowsResynched = (HROW *)JUNK_PTR;
|
|
m_rgRowStatus = (DBROWSTATUS *)JUNK_PTR;
|
|
if (CHECK(ResynchRefresh(DB_NULL_HCHAPTER,1, &hRow, fOverWrite,&m_cRowsResynched,&m_rghRowsResynched, &m_rgRowStatus,FALSE), DB_E_ERRORSOCCURRED))
|
|
{
|
|
COMPARE(m_cRowsResynched,1);
|
|
COMPARE(m_rghRowsResynched[0],DB_NULL_HROW);
|
|
//Increment error count as needed while checking out param values
|
|
CompareOutParams(1, &hRow);
|
|
COMPARE(m_rgRowStatus[0], DBROWSTATUS_E_INVALID);
|
|
|
|
FreeOutParams();
|
|
return TEST_PASS;
|
|
}
|
|
FreeOutParams();
|
|
}
|
|
return TEST_FAIL;
|
|
}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(15)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc ResynchRows/RefreshVisibleData with hRow = hard deleted - DB_E_DELETEDROW
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCPropCanHoldRowsResynch::Variation_15()
|
|
{
|
|
BOOL fResults = FALSE;
|
|
HROW hRow = DB_NULL_HROW;
|
|
BOOL fOverWrite = TRUE;
|
|
|
|
if (m_eTI==TI_IRowsetRefreshFALSE)
|
|
{
|
|
fOverWrite=FALSE;
|
|
}
|
|
ReleaseResynchObjects();
|
|
if (!COMPARE(CreateResynchObjects(m_eTI), TRUE))
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
//Delete the row with this txn
|
|
if (COMPARE(Delete(m_pChgRowset1, &hRow), TRUE))
|
|
{
|
|
m_cRowsResynched = 5;
|
|
m_rghRowsResynched = (HROW *)JUNK_PTR;
|
|
m_rgRowStatus = (DBROWSTATUS *)JUNK_PTR;
|
|
//Check that row status is deleted
|
|
if (CHECK(ResynchRefresh(DB_NULL_HCHAPTER,1, &hRow, fOverWrite, &m_cRowsResynched,&m_rghRowsResynched, &m_rgRowStatus,FALSE), DB_E_ERRORSOCCURRED))
|
|
{
|
|
COMPARE(m_rghRowsResynched[0],hRow);
|
|
COMPARE(m_cRowsResynched,1);
|
|
CompareOutParams(1, &hRow);
|
|
|
|
if (COMPARE(m_rgRowStatus[0], DBROWSTATUS_E_DELETED))
|
|
{
|
|
//if there is no visual cache GetLastVisibleData has
|
|
//to go to the back end.
|
|
//if there is a visual cache GetLastVisibleData sees the delete anyway
|
|
//because it was a hard delete
|
|
if (CHECK(GetLastVisibleData(hRow, m_hChgAccessor, m_pResynchVisibleData,FALSE), DB_E_DELETEDROW))
|
|
{
|
|
fResults = TRUE;
|
|
}
|
|
}
|
|
FreeOutParams();
|
|
}
|
|
}
|
|
//Release the row
|
|
if (hRow != DB_NULL_HROW)
|
|
{
|
|
m_pChgIRowset->ReleaseRows(1, &hRow, NULL, NULL, NULL);
|
|
}
|
|
//We want to release our rowset so the deleted hRow we introduced
|
|
//won't be around for subsequent calls to GetNextRows (which should
|
|
//cause Resynch methods to fail with DELETED ROW)
|
|
ReleaseResynchObjects();
|
|
//Set up for next variation
|
|
COMPARE(CreateResynchObjects(m_eTI), TRUE);
|
|
|
|
if (fResults)
|
|
return TEST_PASS;
|
|
else
|
|
return TEST_FAIL;
|
|
}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(16)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc ResynchRows/RefreshVisibleData with hRow = row deleted by another txn - DB_E_DELETEDROW
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCPropCanHoldRowsResynch::Variation_16()
|
|
{
|
|
HROW hRow = DB_NULL_HROW;
|
|
BOOL fResults = FALSE;
|
|
BOOL fOverWrite = TRUE;
|
|
|
|
if (m_eTI==TI_IRowsetRefreshFALSE)
|
|
{
|
|
fOverWrite=FALSE;
|
|
}
|
|
|
|
ReleaseResynchObjects();
|
|
if (!COMPARE(CreateResynchObjects(m_eTI), TRUE))
|
|
{
|
|
return FALSE;
|
|
}
|
|
//Get row so that provider has it in cache before we change it from another txn
|
|
if (COMPARE(m_pChgRowset1->FindRow(GetNextRowToDelete(), &hRow), TRUE))
|
|
{
|
|
//Delete the row using another txn
|
|
if (COMPARE(Delete(m_pChgRowset2), TRUE))
|
|
{
|
|
//Give Jet time to discover the change
|
|
if (m_fOnAccess)
|
|
Sleep(SLEEP_TIME); //Takes milliseconds as param
|
|
|
|
m_cRowsResynched = 5;
|
|
m_rghRowsResynched = (HROW *)JUNK_PTR;
|
|
m_rgRowStatus = (DBROWSTATUS *)JUNK_PTR;
|
|
if (CHECK(ResynchRefresh(DB_NULL_HCHAPTER,1, &hRow, fOverWrite, &m_cRowsResynched,&m_rghRowsResynched, &m_rgRowStatus,FALSE), DB_E_ERRORSOCCURRED))
|
|
{
|
|
COMPARE(m_rghRowsResynched[0],hRow);
|
|
COMPARE(m_cRowsResynched,1);
|
|
CompareOutParams(1, &hRow);
|
|
|
|
if (COMPARE(m_rgRowStatus[0], DBROWSTATUS_E_DELETED))
|
|
{
|
|
//if there is no visual cache GetLastVisibleData has
|
|
//to go to the back end.
|
|
if (m_eTI==TI_IRowsetResynch || !g_fVisualCache)
|
|
{
|
|
if (CHECK(GetLastVisibleData(hRow, m_hChgAccessor, m_pVisibleData,FALSE), DB_E_DELETEDROW))
|
|
{
|
|
fResults = TRUE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//if this is Refresh and there is a visual cache
|
|
//GetLastVisibleData will succeed. RefreshVisibleData failed,
|
|
//no row was refreshed. GetLastVisibleData gets the current
|
|
//visual cache row value
|
|
if (g_fVisualCache)
|
|
{
|
|
if (CHECK(GetLastVisibleData(hRow, m_hChgAccessor, m_pVisibleData,FALSE), S_OK))
|
|
{
|
|
fResults = TRUE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
FreeOutParams();
|
|
}
|
|
}
|
|
}
|
|
//Release the row
|
|
if (hRow != DB_NULL_HROW)
|
|
{
|
|
m_pChgIRowset->ReleaseRows(1, &hRow, NULL, NULL, NULL);
|
|
}
|
|
//We want to release our rowset so the deleted hRow we introduced
|
|
//won't be around for subsequent calls to GetNextRows (which should
|
|
//cause Resynch methods to fail with DELETED ROW)
|
|
ReleaseResynchObjects();
|
|
//Set up for next variation
|
|
COMPARE(CreateResynchObjects(m_eTI), TRUE);
|
|
|
|
if (fResults)
|
|
return TEST_PASS;
|
|
else
|
|
return TEST_FAIL;
|
|
}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(17)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc GetVisibleData with pData = NULL - E_INVALIDARG
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCPropCanHoldRowsResynch::Variation_17()
|
|
{
|
|
BOOL fResults = FALSE;
|
|
HROW hRow = DB_NULL_HROW;
|
|
|
|
ReleaseResynchObjects();
|
|
if (!COMPARE(CreateResynchObjects(m_eTI), TRUE))
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
//Get valid hRow
|
|
if (COMPARE(m_pChgRowset1->FindRow(GetNextRowToDelete(), &hRow), TRUE))
|
|
{
|
|
//Try all valid params except pData = NULL
|
|
if (CHECK(GetLastVisibleData(hRow, m_hChgAccessor, NULL,FALSE), E_INVALIDARG))
|
|
fResults = TRUE;
|
|
|
|
m_pChgIRowset->ReleaseRows(1, &hRow, NULL, NULL, NULL);
|
|
}
|
|
|
|
if (fResults)
|
|
return TEST_PASS;
|
|
else
|
|
return TEST_FAIL;
|
|
|
|
}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(18)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc GetVisibleData with Null Accessor, pData = NULL
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCPropCanHoldRowsResynch::Variation_18()
|
|
{
|
|
HROW hRow = DB_NULL_HROW;
|
|
HACCESSOR hChgAccessor = DB_NULL_HACCESSOR;
|
|
BOOL fResults = FALSE;
|
|
HRESULT hr;
|
|
ULONG cRefCount = 0;
|
|
BOOL fOverWrite = TRUE;
|
|
|
|
if (m_eTI==TI_IRowsetRefreshFALSE)
|
|
{
|
|
fOverWrite=FALSE;
|
|
}
|
|
|
|
ReleaseResynchObjects();
|
|
if (!COMPARE(CreateResynchObjects(m_eTI), TRUE))
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
if (CHECK(m_pChgRowset1->m_pIAccessor->CreateAccessor(DBACCESSOR_ROWDATA,0, NULL, 0, &hChgAccessor, NULL), S_OK))
|
|
{
|
|
if (ChangeUnderlyingRowAndGetHrow(m_pChgRowset1, ISOLATIONLEVEL_CHAOS, &hRow))
|
|
{
|
|
/////////////////////////////////////////////////////////////////////
|
|
//Use null accessor and NULL pData, so all these should get no data
|
|
/////////////////////////////////////////////////////////////////////
|
|
|
|
//Get data which should already be in the cache
|
|
if (CHECK(m_pChgIRowset->GetData(hRow, hChgAccessor, NULL), S_OK))
|
|
{
|
|
//Resynch the cache
|
|
hr=ResynchRefresh(DB_NULL_HCHAPTER,1,&hRow, fOverWrite, &m_cRowsResynched,&m_rghRowsResynched,&m_rgRowStatus,FALSE);
|
|
if (!hr==S_OK)
|
|
{
|
|
//account for the fact that some providers might delete/insert a row when asked to change it
|
|
//this may put a hole in the rowset and put the newrow somewhere else in the rowset (most likley at the end of the rowset)
|
|
if (DB_S_ERRORSOCCURRED==hr || DB_E_ERRORSOCCURRED == hr)
|
|
{
|
|
if (COMPARE(m_rgRowStatus[0],DBROWSTATUS_E_DELETED))
|
|
{
|
|
COMPARE(1,m_cRowsResynched);
|
|
fResults = TRUE;
|
|
}
|
|
}
|
|
goto CLEANUP;
|
|
}
|
|
else
|
|
{
|
|
CompareOutParams(1, &hRow);
|
|
|
|
//Try to get new visible data
|
|
if (CHECK(GetLastVisibleData(hRow, hChgAccessor,NULL,FALSE), S_OK))
|
|
{
|
|
//Now try to get Newly Resynch'd Data
|
|
if (CHECK(m_pChgIRowset->GetData(hRow, hChgAccessor, NULL), S_OK))
|
|
{
|
|
fResults = TRUE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
CLEANUP:
|
|
FreeOutParams();
|
|
if (hRow != DB_NULL_HROW)
|
|
m_pChgIRowset->ReleaseRows(1, &hRow, NULL, &cRefCount, NULL);
|
|
|
|
if (hChgAccessor != DB_NULL_HACCESSOR)
|
|
if (CHECK(m_pChgRowset1->m_pIAccessor->ReleaseAccessor(hChgAccessor, NULL), S_OK))
|
|
hChgAccessor = DB_NULL_HACCESSOR;
|
|
if (fResults)
|
|
return TEST_PASS;
|
|
else
|
|
return TEST_FAIL;
|
|
}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(19)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc GetVisibleData with Null Accessor, pData valid
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCPropCanHoldRowsResynch::Variation_19()
|
|
{
|
|
HROW hRow = DB_NULL_HROW;
|
|
HACCESSOR hChgAccessor = DB_NULL_HACCESSOR;
|
|
BYTE *pCompareData = NULL;
|
|
BOOL fResults = FALSE;
|
|
HRESULT hr;
|
|
BOOL fOverWrite = TRUE;
|
|
|
|
if (m_eTI==TI_IRowsetRefreshFALSE)
|
|
{
|
|
fOverWrite=FALSE;
|
|
}
|
|
|
|
ReleaseResynchObjects();
|
|
if (!COMPARE(CreateResynchObjects(m_eTI), TRUE))
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
pCompareData = (BYTE *)PROVIDER_ALLOC(m_cbRowSize);
|
|
if (!pCompareData)
|
|
{
|
|
return TEST_FAIL;
|
|
}
|
|
memset(pCompareData,0,(size_t)m_cbRowSize);
|
|
|
|
//Set buffers so we know if they've been touched
|
|
memset(m_pRowsetData, 0, (size_t)m_cbRowSize);
|
|
memset(m_pResynchVisibleData, 0, (size_t)m_cbRowSize);
|
|
memset(m_pResynchRowsetData, 0, (size_t)m_cbRowSize);
|
|
memset(pCompareData, 0, (size_t)m_cbRowSize);
|
|
|
|
if (CHECK(m_pChgRowset1->m_pIAccessor->CreateAccessor(DBACCESSOR_ROWDATA,0, NULL, 0, &hChgAccessor, NULL), S_OK))
|
|
{
|
|
if (ChangeUnderlyingRowAndGetHrow(m_pChgRowset1, ISOLATIONLEVEL_CHAOS, &hRow))
|
|
{
|
|
/////////////////////////////////////////////////////
|
|
//Use null accessor, so all these should get no data
|
|
/////////////////////////////////////////////////////
|
|
|
|
//Get data which should already be in the cache
|
|
if (CHECK(m_pChgIRowset->GetData(hRow, hChgAccessor, m_pRowsetData), S_OK))
|
|
{
|
|
//Resynch the cache
|
|
hr=ResynchRefresh(DB_NULL_HCHAPTER,1,&hRow, fOverWrite, &m_cRowsResynched,&m_rghRowsResynched,&m_rgRowStatus, FALSE);
|
|
if (!hr==S_OK)
|
|
{
|
|
//account for the fact that some providers might delete/insert a row when asked to change it
|
|
//this may put a hole in the rowset and put the newrow somewhere else in the rowset (most likley at the end of the rowset)
|
|
if (DB_S_ERRORSOCCURRED==hr || DB_E_ERRORSOCCURRED == hr)
|
|
{
|
|
if (COMPARE(m_rgRowStatus[0],DBROWSTATUS_E_DELETED))
|
|
{
|
|
COMPARE(1,m_cRowsResynched);
|
|
fResults = TRUE;
|
|
}
|
|
}
|
|
goto CLEANUP;
|
|
}
|
|
else
|
|
{
|
|
if (g_fNOCHANGE)
|
|
{
|
|
//no change was made here, if the provider can handle it, expect it
|
|
COMPARE(m_rgRowStatus[0], DBROWSTATUS_S_NOCHANGE);
|
|
}
|
|
else
|
|
{
|
|
COMPARE(m_rgRowStatus[0], DBROWSTATUS_S_OK);
|
|
}
|
|
|
|
FreeOutParams();
|
|
|
|
//Try to get new visible data
|
|
if (CHECK(GetLastVisibleData(hRow, hChgAccessor,m_pResynchVisibleData,FALSE), S_OK))
|
|
//Now try to get Newly Resynch'd Data
|
|
if (CHECK(m_pChgIRowset->GetData(hRow, hChgAccessor, m_pResynchRowsetData), S_OK))
|
|
//No of the buffers should have been touched, 0 == identical
|
|
if (COMPARE(memcmp(m_pRowsetData, pCompareData, (size_t)m_cbRowSize), 0) &&
|
|
COMPARE(memcmp(m_pResynchVisibleData, pCompareData, (size_t)m_cbRowSize), 0) &&
|
|
COMPARE(memcmp(m_pResynchRowsetData, pCompareData, (size_t)m_cbRowSize), 0))
|
|
{
|
|
fResults = TRUE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
CLEANUP:
|
|
FreeOutParams();
|
|
PROVIDER_FREE(pCompareData);
|
|
|
|
if (hRow != DB_NULL_HROW)
|
|
m_pChgIRowset->ReleaseRows(1, &hRow, NULL, NULL, NULL);
|
|
|
|
if (hChgAccessor != DB_NULL_HACCESSOR)
|
|
CHECK(m_pChgRowset1->m_pIAccessor->ReleaseAccessor(hChgAccessor, NULL), S_OK);
|
|
if (fResults)
|
|
return TEST_PASS;
|
|
else
|
|
return TEST_FAIL;
|
|
}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(20)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc Fetch Position
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCPropCanHoldRowsResynch::Variation_20()
|
|
{
|
|
ReleaseResynchObjects();
|
|
if (!COMPARE(CreateResynchObjects(m_eTI), TRUE))
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
return TestFetchPosition(m_pChgIRowset, m_pChgIRowsetResynch, m_pChgIRowsetRefresh);
|
|
}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(21)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc Rows 1 and n
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCPropCanHoldRowsResynch::Variation_21()
|
|
{
|
|
ReleaseResynchObjects();
|
|
if (!COMPARE(CreateResynchObjects(m_eTI), TRUE))
|
|
{
|
|
return FALSE;
|
|
}
|
|
return TestRows1AndN(m_pChgIRowset, m_pChgIRowsetResynch, m_pChgIRowsetRefresh);
|
|
}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(22)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc All Rows
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCPropCanHoldRowsResynch::Variation_22()
|
|
{
|
|
ReleaseResynchObjects();
|
|
if (!COMPARE(CreateResynchObjects(m_eTI), TRUE))
|
|
{
|
|
return FALSE;
|
|
}
|
|
return TestAllRows(m_pChgIRowset, m_pChgIRowsetResynch, m_pChgIRowsetRefresh);
|
|
}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(23)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc ResynchRows with rghRows = NULL - E_INVALIDARG
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCPropCanHoldRowsResynch::Variation_23()
|
|
{
|
|
BOOL fOverWrite = TRUE;
|
|
|
|
if (m_eTI==TI_IRowsetRefreshFALSE)
|
|
{
|
|
fOverWrite=FALSE;
|
|
}
|
|
|
|
ReleaseResynchObjects();
|
|
if (!COMPARE(CreateResynchObjects(m_eTI), TRUE))
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
//All valid args except rghRows
|
|
if (CHECK(ResynchRefresh(DB_NULL_HCHAPTER,1, NULL, fOverWrite, &m_cRowsResynched, &m_rghRowsResynched, &m_rgRowStatus,FALSE), E_INVALIDARG))
|
|
{
|
|
//Make sure all out parameters are zeroed/nulled out on error
|
|
CheckOutParamsAreNulled();
|
|
FreeOutParams();
|
|
|
|
return TEST_PASS;
|
|
}
|
|
else
|
|
{
|
|
FreeOutParams();
|
|
return TEST_FAIL;
|
|
}
|
|
}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(24)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc ResynchRows with one invalid hRow - DBROWSTATUS_E_INVALID
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCPropCanHoldRowsResynch::Variation_24()
|
|
{
|
|
HROW *phRows = NULL;
|
|
BOOL fResults = FALSE;
|
|
HROW hSaveRow = DB_NULL_HROW;
|
|
DBCOUNTITEM cRowsObtained = 0;
|
|
ULONG i = 0;
|
|
BOOL fOverWrite = TRUE;
|
|
|
|
if (m_eTI==TI_IRowsetRefreshFALSE)
|
|
{
|
|
fOverWrite=FALSE;
|
|
}
|
|
|
|
ReleaseResynchObjects();
|
|
if (!COMPARE(CreateResynchObjects(m_eTI), TRUE))
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
//Make sure we are at beginning of rowset after other variations
|
|
CHECK(m_pChgIRowset->RestartPosition(NULL), S_OK);
|
|
|
|
//Get all the rows, ask for more than enough
|
|
if (CHECK(m_pChgIRowset->GetNextRows(NULL, 0, NUM_ROWS * 3, &cRowsObtained, &phRows), DB_S_ENDOFROWSET))
|
|
{
|
|
//Now make one of the elements invalid
|
|
hSaveRow = phRows[cRowsObtained/2];
|
|
phRows[cRowsObtained/2] = DB_NULL_HROW;
|
|
|
|
//Resynch all the rows
|
|
if (CHECK(ResynchRefresh(DB_NULL_HCHAPTER,cRowsObtained, phRows, fOverWrite,&m_cRowsResynched, &m_rghRowsResynched, &m_rgRowStatus,FALSE), DB_S_ERRORSOCCURRED))
|
|
{
|
|
CompareOutParams(cRowsObtained, phRows);
|
|
|
|
//Verify status is correct for each element
|
|
for (i=0; i<cRowsObtained; i++)
|
|
{
|
|
if (i == cRowsObtained /2)
|
|
COMPARE(m_rgRowStatus[i], DBROWSTATUS_E_INVALID);
|
|
else
|
|
{
|
|
if (g_fNOCHANGE)
|
|
{
|
|
//no change was made here, if the provider can handle it, expect it
|
|
COMPARE(m_rgRowStatus[i], DBROWSTATUS_S_NOCHANGE);
|
|
}
|
|
else
|
|
{
|
|
COMPARE(m_rgRowStatus[i], DBROWSTATUS_S_OK);
|
|
}
|
|
}
|
|
}
|
|
fResults = TRUE;
|
|
}
|
|
|
|
//Move our munged row back so we can free whole array
|
|
phRows[cRowsObtained/2] = hSaveRow;
|
|
|
|
CHECK(m_pChgIRowset->ReleaseRows(cRowsObtained, phRows, NULL, NULL, NULL), S_OK);
|
|
|
|
if (phRows)
|
|
{
|
|
PROVIDER_FREE(phRows);
|
|
}
|
|
}
|
|
FreeOutParams();
|
|
|
|
if (fResults)
|
|
return TEST_PASS;
|
|
else
|
|
return TEST_FAIL;
|
|
}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(25)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc ResynchRows with all invalid hRows - DBROWSTATUS_E_INVALID
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCPropCanHoldRowsResynch::Variation_25()
|
|
{
|
|
HROW rgRows[NUM_ROWS*2];
|
|
ULONG i;
|
|
BOOL fOverWrite = TRUE;
|
|
|
|
if (m_eTI==TI_IRowsetRefreshFALSE)
|
|
{
|
|
fOverWrite=FALSE;
|
|
}
|
|
|
|
ReleaseResynchObjects();
|
|
if (!COMPARE(CreateResynchObjects(m_eTI), TRUE))
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
//Make all hRows invalid
|
|
for (i=0; i< (NUM_ROWS*2); i++)
|
|
{
|
|
rgRows[i] = DB_NULL_HROW;
|
|
}
|
|
m_cRowsResynched = 5;
|
|
m_rghRowsResynched = (HROW *)JUNK_PTR;
|
|
m_rgRowStatus = (DBROWSTATUS *)JUNK_PTR;
|
|
//Try to Resynch all the invalid rows
|
|
if (CHECK(ResynchRefresh(DB_NULL_HCHAPTER,(NUM_ROWS*2), rgRows, fOverWrite, &m_cRowsResynched, &m_rghRowsResynched, &m_rgRowStatus, FALSE), DB_E_ERRORSOCCURRED))
|
|
{
|
|
for (i=0; i< (NUM_ROWS*2); i++)
|
|
{
|
|
COMPARE(m_rghRowsResynched[i],DB_NULL_HROW);
|
|
}
|
|
COMPARE(m_cRowsResynched,(NUM_ROWS*2));
|
|
CompareOutParams((NUM_ROWS*2), rgRows);
|
|
|
|
for (i=0; i<(NUM_ROWS*2); i++)
|
|
{
|
|
COMPARE(m_rgRowStatus[i], DBROWSTATUS_E_INVALID);
|
|
}
|
|
FreeOutParams();
|
|
|
|
return TEST_PASS;
|
|
}
|
|
FreeOutParams();
|
|
return TEST_FAIL;
|
|
|
|
}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(26)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc ResynchRows with cRows = 0 and no active hRows
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCPropCanHoldRowsResynch::Variation_26()
|
|
{
|
|
BOOL fOverWrite = TRUE;
|
|
|
|
if (m_eTI==TI_IRowsetRefreshFALSE)
|
|
{
|
|
fOverWrite=FALSE;
|
|
}
|
|
ReleaseResynchObjects();
|
|
if (!COMPARE(CreateResynchObjects(m_eTI), TRUE))
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
HROW * pJunkHRow = (HROW *)JUNK_PTR;
|
|
|
|
//Make sure pJunkHrow is ignored with cRows is 0
|
|
if (CHECK(ResynchRefresh(DB_NULL_HCHAPTER,0, pJunkHRow, fOverWrite, &m_cRowsResynched, &m_rghRowsResynched, &m_rgRowStatus,FALSE), S_OK))
|
|
{
|
|
//The three output params should be nulled/zeroed out
|
|
CheckOutParamsAreNulled();
|
|
FreeOutParams();
|
|
|
|
return TEST_PASS;
|
|
}
|
|
|
|
FreeOutParams();
|
|
return TEST_FAIL;
|
|
|
|
|
|
}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(27)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc IRowsetResynch with held hRows from different GetNextRows calls, cRows=0
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCPropCanHoldRowsResynch::Variation_27()
|
|
{
|
|
HROW rghRow[2];
|
|
HROW *phRows1 = &rghRow[0];
|
|
HROW *phRows2 = &rghRow[1];
|
|
BOOL fResults = FALSE;
|
|
DBCOUNTITEM cRowsObtained = 0;
|
|
BOOL fOverWrite = TRUE;
|
|
|
|
if (m_eTI==TI_IRowsetRefreshFALSE)
|
|
{
|
|
fOverWrite=FALSE;
|
|
}
|
|
|
|
ReleaseResynchObjects();
|
|
if (!COMPARE(CreateResynchObjects(m_eTI), TRUE))
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
//Make sure we are at beginning of rowset after other variations
|
|
CHECK(m_pChgIRowset->RestartPosition(NULL), S_OK);
|
|
//Get one row
|
|
if (CHECK(m_pChgIRowset->GetNextRows(NULL, 0, 1, &cRowsObtained, &phRows1), S_OK))
|
|
{
|
|
//Get another row
|
|
if (CHECK(m_pChgIRowset->GetNextRows(NULL, 0, 1, &cRowsObtained, &phRows2), S_OK))
|
|
{
|
|
//Resynch all the rows from multiple GetNextRows calls
|
|
if (CHECK(ResynchRefresh(DB_NULL_HCHAPTER,0, NULL, fOverWrite, &m_cRowsResynched, &m_rghRowsResynched, &m_rgRowStatus,FALSE), S_OK))
|
|
{
|
|
//Even though we got the hRows in two calls,
|
|
//we put consecutively in one array
|
|
CompareOutParams(2, rghRow);
|
|
|
|
if (g_fNOCHANGE)
|
|
|
|
{
|
|
//no change was made here, if the provider can handle it, expect it
|
|
COMPARE(m_rgRowStatus[0], DBROWSTATUS_S_NOCHANGE);
|
|
COMPARE(m_rgRowStatus[1], DBROWSTATUS_S_NOCHANGE);
|
|
}
|
|
else
|
|
{
|
|
COMPARE(m_rgRowStatus[1], DBROWSTATUS_S_OK);
|
|
COMPARE(m_rgRowStatus[1], DBROWSTATUS_S_OK);
|
|
}
|
|
|
|
fResults = TRUE;
|
|
}
|
|
|
|
//Release second row
|
|
CHECK(m_pChgIRowset->ReleaseRows(1, phRows2, NULL, NULL, NULL), S_OK);
|
|
}
|
|
|
|
//Release first row
|
|
CHECK(m_pChgIRowset->ReleaseRows(1, phRows1, NULL, NULL, NULL), S_OK);
|
|
}
|
|
FreeOutParams();
|
|
if (fResults)
|
|
return TEST_PASS;
|
|
else
|
|
return TEST_FAIL;
|
|
}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(28)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc ResynchRows/RefreshVisibleData with held hRows from different GetNextRows calls, cRows exact
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCPropCanHoldRowsResynch::Variation_28()
|
|
{
|
|
HROW rghRow[2];
|
|
HROW *phRows1 = &rghRow[0];
|
|
HROW *phRows2 = &rghRow[1];
|
|
BOOL fResults = FALSE;
|
|
DBCOUNTITEM cRowsObtained = 0;
|
|
BOOL fOverWrite = TRUE;
|
|
|
|
if (m_eTI==TI_IRowsetRefreshFALSE)
|
|
{
|
|
fOverWrite=FALSE;
|
|
}
|
|
|
|
ReleaseResynchObjects();
|
|
if (!COMPARE(CreateResynchObjects(m_eTI), TRUE))
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
//Make sure we are at beginning of rowset after other variations
|
|
CHECK(m_pChgIRowset->RestartPosition(NULL), S_OK);
|
|
//Get one row
|
|
if (CHECK(m_pChgIRowset->GetNextRows(NULL, 0, 1, &cRowsObtained, &phRows1), S_OK))
|
|
{
|
|
//Get another row
|
|
if (CHECK(m_pChgIRowset->GetNextRows(NULL, 0, 1, &cRowsObtained, &phRows2), S_OK))
|
|
{
|
|
//Resynch all the rows from multiple GetNextRows calls, using
|
|
//exact hRows rather than cRows = 0
|
|
if (CHECK(ResynchRefresh(DB_NULL_HCHAPTER,2, rghRow, fOverWrite, &m_cRowsResynched, &m_rghRowsResynched, &m_rgRowStatus,FALSE), S_OK))
|
|
{
|
|
//Even though we got the hRows in two calls,
|
|
//we put consecutively in one array
|
|
CompareOutParams(2, rghRow);
|
|
|
|
if (g_fNOCHANGE)
|
|
|
|
{
|
|
//no change was made here, if the provider can handle it, expect it
|
|
COMPARE(m_rgRowStatus[0], DBROWSTATUS_S_NOCHANGE);
|
|
COMPARE(m_rgRowStatus[1], DBROWSTATUS_S_NOCHANGE);
|
|
}
|
|
else
|
|
{
|
|
COMPARE(m_rgRowStatus[1], DBROWSTATUS_S_OK);
|
|
COMPARE(m_rgRowStatus[1], DBROWSTATUS_S_OK);
|
|
}
|
|
|
|
FreeOutParams();
|
|
|
|
fResults = TRUE;
|
|
}
|
|
|
|
//Release second row
|
|
CHECK(m_pChgIRowset->ReleaseRows(1, phRows2, NULL, NULL, NULL), S_OK);
|
|
}
|
|
|
|
//Release first row
|
|
CHECK(m_pChgIRowset->ReleaseRows(1, phRows1, NULL, NULL, NULL), S_OK);
|
|
}
|
|
if (fResults)
|
|
return TEST_PASS;
|
|
else
|
|
return TEST_FAIL;
|
|
}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(29)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc Fetch Position with Read Only Rowset
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCPropCanHoldRowsResynch::Variation_29()
|
|
{
|
|
ReleaseResynchObjects();
|
|
if (!COMPARE(CreateResynchObjects(m_eTI), TRUE))
|
|
{
|
|
return FALSE;
|
|
}
|
|
return TestFetchPosition(m_pROIRowset, m_pROIRowsetResynch, m_pROIRowsetRefresh);
|
|
}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(30)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc Rows 1 and n with Read Only Rowset
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCPropCanHoldRowsResynch::Variation_30()
|
|
{
|
|
ReleaseResynchObjects();
|
|
if (!COMPARE(CreateResynchObjects(m_eTI), TRUE))
|
|
{
|
|
return FALSE;
|
|
}
|
|
return TestRows1AndN(m_pROIRowset, m_pROIRowsetResynch, m_pROIRowsetRefresh);
|
|
}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(31)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc All Rows with Read Only Rowset
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCPropCanHoldRowsResynch::Variation_31()
|
|
{
|
|
ReleaseResynchObjects();
|
|
if (!COMPARE(CreateResynchObjects(m_eTI), TRUE))
|
|
{
|
|
return FALSE;
|
|
}
|
|
return TestAllRows(m_pROIRowset, m_pROIRowsetResynch, m_pROIRowsetRefresh);
|
|
}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(32)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc IRowsetResynch with hRow = DB_NULL_HROW - DB_E_BADROWHANDLE
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCPropCanHoldRowsResynch::Variation_32()
|
|
{
|
|
HROW hRow = DB_NULL_HROW;
|
|
BOOL fOverWrite = TRUE;
|
|
|
|
if (m_eTI==TI_IRowsetRefreshFALSE)
|
|
{
|
|
fOverWrite=FALSE;
|
|
}
|
|
|
|
ReleaseResynchObjects();
|
|
if (!COMPARE(CreateResynchObjects(m_eTI), TRUE))
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
//Note, provider not required to check for this return code
|
|
if (CHECK(GetLastVisibleData(hRow, m_hChgAccessor, m_pVisibleData,FALSE), DB_E_BADROWHANDLE))
|
|
{
|
|
m_rghRowsResynched = (HROW *)JUNK_PTR;
|
|
m_rgRowStatus = (DBROWSTATUS *)JUNK_PTR;
|
|
if (CHECK(ResynchRefresh(DB_NULL_HCHAPTER,1, &hRow, fOverWrite, NULL,&m_rghRowsResynched, &m_rgRowStatus, FALSE), DB_E_ERRORSOCCURRED))
|
|
{
|
|
if(COMPARE(m_rgRowStatus,(DBROWSTATUS *)JUNK_PTR),TRUE)
|
|
{
|
|
if(COMPARE(m_rghRowsResynched,(HROW *)JUNK_PTR),TRUE)
|
|
{
|
|
return TEST_PASS;
|
|
}
|
|
}
|
|
FreeOutParams();
|
|
}
|
|
}
|
|
FreeOutParams();
|
|
return TEST_FAIL;
|
|
}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(33)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc ResynchRows/RefreshVisibleData with held cRows=0 and all params NULL
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCPropCanHoldRowsResynch::Variation_33()
|
|
{
|
|
HROW rghRow[2];
|
|
HROW *phRows1 = &rghRow[0];
|
|
HROW *phRows2 = &rghRow[1];
|
|
BOOL fResults = FALSE;
|
|
DBCOUNTITEM cRowsObtained = 0;
|
|
BOOL fOverWrite = TRUE;
|
|
|
|
if (m_eTI==TI_IRowsetRefreshFALSE)
|
|
{
|
|
fOverWrite=FALSE;
|
|
}
|
|
|
|
ReleaseResynchObjects();
|
|
if (!COMPARE(CreateResynchObjects(m_eTI), TRUE))
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
//Make sure we are at beginning of rowset after other variations
|
|
CHECK(m_pChgIRowset->RestartPosition(NULL), S_OK);
|
|
//Get one row
|
|
if (CHECK(m_pChgIRowset->GetNextRows(NULL, 0, 1, &cRowsObtained, &phRows1), S_OK))
|
|
{
|
|
//Get another row
|
|
if (CHECK(m_pChgIRowset->GetNextRows(NULL, 0, 1, &cRowsObtained, &phRows2), S_OK))
|
|
{
|
|
//Resynch all the rows from multiple GetNextRows calls
|
|
if (CHECK(ResynchRefresh(DB_NULL_HCHAPTER,0, NULL, fOverWrite, NULL, NULL, NULL, FALSE), S_OK))
|
|
{
|
|
fResults = TRUE;
|
|
}
|
|
//Release second row
|
|
CHECK(m_pChgIRowset->ReleaseRows(1, phRows2, NULL, NULL, NULL), S_OK);
|
|
}
|
|
//Release first row
|
|
CHECK(m_pChgIRowset->ReleaseRows(1, phRows1, NULL, NULL, NULL), S_OK);
|
|
}
|
|
|
|
if (fResults)
|
|
return TEST_PASS;
|
|
else
|
|
return TEST_FAIL;
|
|
}
|
|
// }}
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(34)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc ResynchRows with one invalid hRow - no params
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCPropCanHoldRowsResynch::Variation_34()
|
|
{
|
|
HROW *phRows = NULL;
|
|
BOOL fResults = FALSE;
|
|
HROW hSaveRow = DB_NULL_HROW;
|
|
DBCOUNTITEM cRowsObtained = 0;
|
|
ULONG i = 0;
|
|
BOOL fOverWrite = TRUE;
|
|
|
|
if (m_eTI==TI_IRowsetRefreshFALSE)
|
|
{
|
|
fOverWrite=FALSE;
|
|
}
|
|
|
|
ReleaseResynchObjects();
|
|
if (!COMPARE(CreateResynchObjects(m_eTI), TRUE))
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
//Make sure we are at beginning of rowset after other variations
|
|
CHECK(m_pChgIRowset->RestartPosition(NULL), S_OK);
|
|
|
|
//Get all the rows, ask for more than enough
|
|
if (CHECK(m_pChgIRowset->GetNextRows(NULL, 0, NUM_ROWS * 3, &cRowsObtained, &phRows), DB_S_ENDOFROWSET))
|
|
{
|
|
//Now make one of the elements invalid
|
|
hSaveRow = phRows[cRowsObtained/2];
|
|
phRows[cRowsObtained/2] = DB_NULL_HROW;
|
|
|
|
//Resynch all the rows
|
|
if (CHECK(ResynchRefresh(DB_NULL_HCHAPTER,cRowsObtained, phRows, fOverWrite, NULL, NULL, NULL, FALSE), DB_S_ERRORSOCCURRED))
|
|
{
|
|
fResults = TRUE;
|
|
}
|
|
|
|
//Move our munged row back so we can free whole array
|
|
phRows[cRowsObtained/2] = hSaveRow;
|
|
|
|
CHECK(m_pChgIRowset->ReleaseRows(cRowsObtained, phRows, NULL, NULL, NULL), S_OK);
|
|
|
|
if (phRows)
|
|
{
|
|
PROVIDER_FREE(phRows);
|
|
}
|
|
}
|
|
|
|
if (fResults)
|
|
return TEST_PASS;
|
|
else
|
|
return TEST_FAIL;
|
|
}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(35)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc Hard inserted row
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCPropCanHoldRowsResynch::Variation_35()
|
|
{
|
|
HROW hRow = DB_NULL_HROW;
|
|
BOOL fResults = FALSE;
|
|
HRESULT hr;
|
|
BOOL fOverWrite = TRUE;
|
|
|
|
if (m_eTI==TI_IRowsetRefreshFALSE)
|
|
{
|
|
fOverWrite=FALSE;
|
|
}
|
|
|
|
ReleaseResynchObjects();
|
|
if (!COMPARE(CreateResynchObjects(m_eTI), TRUE))
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
//Now try resynch methods on hard inserted row.
|
|
if (m_pChgRowset1->Insert(GetNextRowToInsert(), &hRow))
|
|
{
|
|
//g_ulLastActualInsert++;
|
|
g_InsertIncrement();
|
|
|
|
m_cRowsResynched = 5;
|
|
m_rghRowsResynched = (HROW *)JUNK_PTR;
|
|
m_rgRowStatus = (DBROWSTATUS *)JUNK_PTR;
|
|
//Now try resynch methods on inserted row
|
|
hr = ResynchRefresh(DB_NULL_HCHAPTER,1, &hRow, fOverWrite, &m_cRowsResynched, &m_rghRowsResynched, &m_rgRowStatus,FALSE);
|
|
|
|
//have strong identity support? can newly inserted rows be compared?
|
|
if (m_fStrongIdentity)
|
|
{
|
|
COMPARE(S_OK,hr);
|
|
}
|
|
else
|
|
{
|
|
COMPARE(m_cRowsResynched,1);
|
|
COMPARE(m_rghRowsResynched[0],hRow);
|
|
CompareOutParams(1, &hRow);
|
|
|
|
COMPARE(m_rgRowStatus[0], DBROWSTATUS_E_NEWLYINSERTED);
|
|
}
|
|
|
|
hr = GetLastVisibleData(hRow, m_hChgAccessor,m_pResynchVisibleData,FALSE);
|
|
|
|
//have strong identity support? can newly inserted rows be compared?
|
|
if (m_fStrongIdentity)
|
|
{
|
|
COMPARE(S_OK,hr);
|
|
}
|
|
else
|
|
{
|
|
COMPARE(DB_E_NEWLYINSERTED,hr);
|
|
}
|
|
|
|
//Next GetData
|
|
if (SUCCEEDED(m_pChgIRowset->GetData(hRow, m_hChgAccessor, m_pResynchRowsetData)))
|
|
{
|
|
fResults = TRUE;
|
|
}
|
|
//no change is made, these should be the same
|
|
if(CompareBuffer(m_pResynchVisibleData,m_pResynchRowsetData,m_cBindings,m_rgBindings,m_pIMalloc,FALSE,FALSE,COMPARE_ONLY)!=TRUE)
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
}
|
|
CLEANUP:
|
|
FreeOutParams();
|
|
if (hRow != DB_NULL_HROW)
|
|
{
|
|
m_pChgIRowset->ReleaseRows(1, &hRow, NULL, NULL, NULL);
|
|
}
|
|
if (fResults)
|
|
return TEST_PASS;
|
|
else
|
|
return TEST_FAIL;
|
|
|
|
}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(36)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc ResynchRows/RefreshVisibleData with hRow = hard deleted - no params - no op
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCPropCanHoldRowsResynch::Variation_36()
|
|
{
|
|
BOOL fResults = FALSE;
|
|
HROW hRow = DB_NULL_HROW;
|
|
HROW rghRow[1];
|
|
HROW *phRows = &rghRow[0];
|
|
DBCOUNTITEM cRowsObtained = 0;
|
|
BOOL fOverWrite = TRUE;
|
|
|
|
if (m_eTI==TI_IRowsetRefreshFALSE)
|
|
{
|
|
fOverWrite=FALSE;
|
|
}
|
|
ReleaseResynchObjects();
|
|
if (!COMPARE(CreateResynchObjects(m_eTI), TRUE))
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
if (CHECK(m_pChgIRowset->GetNextRows(NULL, 0, 1, &cRowsObtained, &phRows), S_OK))
|
|
{
|
|
//Release the row
|
|
if (*phRows != DB_NULL_HROW)
|
|
{
|
|
m_pChgIRowset->ReleaseRows(1, phRows, NULL, NULL, NULL);
|
|
}
|
|
//Delete the row
|
|
if (COMPARE(Delete(m_pChgRowset1, &hRow), TRUE))
|
|
{
|
|
m_cRowsResynched = 5;
|
|
m_rghRowsResynched = (HROW *)JUNK_PTR;
|
|
m_rgRowStatus = (DBROWSTATUS *)JUNK_PTR;
|
|
//the row has been deleted, resynch deleted row
|
|
if (CHECK(ResynchRefresh(DB_NULL_HCHAPTER,0, NULL, fOverWrite, &m_cRowsResynched,&m_rghRowsResynched, &m_rgRowStatus,FALSE), DB_E_ERRORSOCCURRED))
|
|
{
|
|
COMPARE(m_cRowsResynched,1);
|
|
//COMPARE(m_rghRowsResynched[0],hRow);
|
|
if (COMPARE(m_rgRowStatus[0], DBROWSTATUS_E_DELETED))
|
|
{
|
|
if (CHECK(GetLastVisibleData(hRow, m_hChgAccessor, m_pVisibleData,FALSE), DB_E_DELETEDROW))
|
|
{
|
|
fResults = TRUE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
//free some mem
|
|
FreeOutParams();
|
|
//Release the row
|
|
if (hRow != DB_NULL_HROW)
|
|
{
|
|
m_pChgIRowset->ReleaseRows(1, &hRow, NULL, NULL, NULL);
|
|
}
|
|
//We want to release our rowset so the deleted hRow we introduced
|
|
//won't be around for subsequent calls to GetNextRows (which should
|
|
//cause Resynch methods to fail with DELETED ROW)
|
|
ReleaseResynchObjects();
|
|
//Set up for next variation
|
|
COMPARE(CreateResynchObjects(m_eTI), TRUE);
|
|
|
|
if (fResults)
|
|
return TEST_PASS;
|
|
else
|
|
return TEST_FAIL;
|
|
}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(37)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc GetVisibleData with released HROW - DB_E_BADROWHANDLE
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCPropCanHoldRowsResynch::Variation_37()
|
|
{
|
|
BOOL fResults = FALSE;
|
|
HROW hRow = DB_NULL_HROW;
|
|
ULONG cRowsObtained = 0;
|
|
|
|
//If no provider support for this isolation level, just return pass
|
|
if (!m_fChaos && !m_fReadUncommitted && !m_fReadCommitted &&
|
|
!m_fRepeatableRead && !m_fSerializable)
|
|
{
|
|
odtLog << wszNoProviderSupport << L"ANY" << wszNewLine;
|
|
return TEST_PASS;
|
|
}
|
|
|
|
//Not all drivers allow starting a txn with rowsets
|
|
//open, so release them before starting a txn
|
|
ReleaseResynchObjects();
|
|
|
|
//Set the highest possible isolation level, to make this test interesting
|
|
//since regardless of isolation, we should always see our own change.
|
|
//Note that we only start a txn for this rowset and not the RORowset,
|
|
//since otherwise the RORowset could lock us from changing
|
|
//due to the high isolation level
|
|
CHECK(m_pChgRowset1->m_pITxnLocal->StartTransaction(m_fHighestSupportedIsoLevel, 0, NULL, NULL), S_OK);
|
|
|
|
COMPARE(CreateResynchObjects(m_eTI), TRUE);
|
|
|
|
//Change a row ourselves and keep hRow
|
|
COMPARE(m_pChgRowset1->Change(GetNextRowToDelete(), GetNextRowToInsert(), &hRow), TRUE);
|
|
|
|
m_pChgIRowset->ReleaseRows(1, &hRow, NULL, NULL, NULL);
|
|
|
|
//Now GetVisibleData on the released row
|
|
CHECK(GetLastVisibleData(hRow, m_hChgAccessor, m_pVisibleData,FALSE),DB_E_BADROWHANDLE);
|
|
|
|
fResults = TRUE;
|
|
|
|
COMPARE(EndTxns(TRUE), TRUE);
|
|
|
|
if (hRow != DB_NULL_HROW)
|
|
m_pChgIRowset->ReleaseRows(1, &hRow, NULL, NULL, NULL);
|
|
|
|
if (fResults)
|
|
return TEST_PASS;
|
|
else
|
|
return TEST_FAIL;
|
|
}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(38)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc SetData with all status IGNORE
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCPropCanHoldRowsResynch::Variation_38()
|
|
{
|
|
BOOL fResults = FALSE;
|
|
HROW hRow = DB_NULL_HROW;
|
|
ULONG cRowsObtained = 0;
|
|
HRESULT hr;
|
|
BOOL fOverWrite = TRUE;
|
|
|
|
if (m_eTI==TI_IRowsetRefreshFALSE)
|
|
{
|
|
fOverWrite=FALSE;
|
|
}
|
|
|
|
//If no provider support for this isolation level, just return pass
|
|
if (!m_fChaos && !m_fReadUncommitted && !m_fReadCommitted &&
|
|
!m_fRepeatableRead && !m_fSerializable)
|
|
{
|
|
odtLog << wszNoProviderSupport << L"ANY" << wszNewLine;
|
|
return TEST_PASS;
|
|
}
|
|
|
|
//Not all drivers allow starting a txn with rowsets
|
|
//open, so release them before starting a txn
|
|
ReleaseResynchObjects();
|
|
|
|
//Set the highest possible isolation level, to make this test interesting
|
|
//since regardless of isolation, we should always see our own change.
|
|
//Note that we only start a txn for this rowset and not the RORowset,
|
|
//since otherwise the RORowset could lock us from changing
|
|
//due to the high isolation level
|
|
CHECK(m_pChgRowset1->m_pITxnLocal->StartTransaction(m_fHighestSupportedIsoLevel, 0, NULL, NULL), S_OK);
|
|
|
|
COMPARE(CreateResynchObjects(m_eTI), TRUE);
|
|
|
|
//Get row so that provider has it in cache before we change it from another txn
|
|
COMPARE(m_pChgRowset1->FindRow(GetNextRowToDelete(), &hRow), TRUE);
|
|
|
|
//Now Get Data
|
|
CHECK(m_pChgIRowset->GetData(hRow, m_hChgAccessor, m_pRowsetData), S_OK);
|
|
|
|
//Change a row with DBSTATUS_S_IGNORE as the status
|
|
COMPARE(m_pChgRowset1->Change(GetNextRowToDelete(), GetNextRowToInsert(), NULL, TRUE), TRUE);
|
|
|
|
//do a ResynchRows(0/NULL) to check what is brought in
|
|
hr = ResynchRefresh(DB_NULL_HCHAPTER,0, NULL, fOverWrite,&m_cRowsResynched, &m_rghRowsResynched, &m_rgRowStatus,FALSE);
|
|
if (!hr==S_OK)
|
|
{
|
|
//account for the fact that some providers might delete/insert a row when asked to change it
|
|
//this may put a hole in the rowset and put the newrow somewhere else in the rowset (most likley at the end of the rowset)
|
|
if (DB_E_DELETEDROW==hr)
|
|
{
|
|
fResults = TRUE;
|
|
goto CLEANUP;
|
|
}
|
|
else
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
}
|
|
|
|
if (m_cRowsResynched)
|
|
{
|
|
//Now Get Resynch'd Data
|
|
CHECK(m_pChgIRowset->GetData(m_rghRowsResynched[0], m_hChgAccessor, m_pResynchRowsetData), S_OK);
|
|
|
|
//Now GetVisibleData on the same row
|
|
CHECK(GetLastVisibleData(m_rghRowsResynched[0], m_hChgAccessor, m_pResynchVisibleData,FALSE),S_OK);
|
|
|
|
//no change is made, these should be the same
|
|
COMPARE(CompareBuffer(m_pResynchVisibleData,m_pRowsetData,m_cBindings,m_rgBindings,m_pIMalloc,FALSE,FALSE,COMPARE_ONLY),TRUE);
|
|
COMPARE(CompareBuffer(m_pResynchVisibleData,m_pResynchRowsetData,m_cBindings,m_rgBindings,m_pIMalloc,FALSE,FALSE,COMPARE_ONLY),TRUE);
|
|
|
|
//Everything went OK
|
|
fResults = TRUE;
|
|
}
|
|
CLEANUP:
|
|
FreeOutParams();
|
|
|
|
COMPARE(EndTxns(TRUE), TRUE);
|
|
|
|
if (hRow != DB_NULL_HROW)
|
|
m_pChgIRowset->ReleaseRows(1, &hRow, NULL, NULL, NULL);
|
|
|
|
if (fResults)
|
|
return TEST_PASS;
|
|
else
|
|
return TEST_FAIL;
|
|
}
|
|
// }}
|
|
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(39)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc SetData with all status DEFAULT
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCPropCanHoldRowsResynch::Variation_39()
|
|
{
|
|
BOOL fResults = FALSE;
|
|
HROW hRow = DB_NULL_HROW;
|
|
ULONG cRowsObtained = 0;
|
|
HRESULT hr;
|
|
BOOL fOverWrite = TRUE;
|
|
ULONG i = 0;
|
|
|
|
|
|
if (m_eTI==TI_IRowsetRefreshFALSE)
|
|
{
|
|
fOverWrite=FALSE;
|
|
}
|
|
|
|
//If no provider support for this isolation level, just return pass
|
|
if (!m_fChaos && !m_fReadUncommitted && !m_fReadCommitted &&
|
|
!m_fRepeatableRead && !m_fSerializable)
|
|
{
|
|
odtLog << wszNoProviderSupport << L"ANY" << wszNewLine;
|
|
return TEST_PASS;
|
|
}
|
|
|
|
//Not all drivers allow starting a txn with rowsets
|
|
//open, so release them before starting a txn
|
|
ReleaseResynchObjects();
|
|
|
|
//Set the highest possible isolation level, to make this test interesting
|
|
//since regardless of isolation, we should always see our own change.
|
|
//Note that we only start a txn for this rowset and not the RORowset,
|
|
//since otherwise the RORowset could lock us from changing
|
|
//due to the high isolation level
|
|
CHECK(m_pChgRowset1->m_pITxnLocal->StartTransaction(m_fHighestSupportedIsoLevel, 0, NULL, NULL), S_OK);
|
|
|
|
COMPARE(CreateResynchObjects(m_eTI), TRUE);
|
|
|
|
//Get row so that provider has it in cache before we change it from another txn
|
|
COMPARE(m_pChgRowset1->FindRow(GetNextRowToDelete(), &hRow), TRUE);
|
|
|
|
//Now Get Data
|
|
CHECK(m_pChgIRowset->GetData(hRow, m_hChgAccessor, m_pRowsetData), S_OK);
|
|
|
|
//Change a row with DBSTATUS_S_DEFAULT as the status
|
|
COMPARE(m_pChgRowset1->Change(GetNextRowToDelete(), GetNextRowToInsert(), NULL, FALSE, TRUE), TRUE);
|
|
|
|
//do a ResynchRows(0/NULL) to check what is brought in
|
|
hr = ResynchRefresh(DB_NULL_HCHAPTER,0, NULL, fOverWrite,&m_cRowsResynched, &m_rghRowsResynched, &m_rgRowStatus,FALSE);
|
|
if (hr!=S_OK)
|
|
{
|
|
//account for the fact that some providers might delete/insert a row when asked to change it
|
|
//this may put a hole in the rowset and put the newrow somewhere else in the rowset (most likley at the end of the rowset)
|
|
if (DB_E_ERRORSOCCURRED==hr)
|
|
{
|
|
COMPARE(1,m_cRowsResynched);
|
|
COMPARE(m_rgRowStatus[0],DBROWSTATUS_E_DELETED);
|
|
fResults = TRUE;
|
|
goto CLEANUP;
|
|
}
|
|
else
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
}
|
|
|
|
if (m_cRowsResynched)
|
|
{
|
|
if (fOverWrite)
|
|
{
|
|
//Now Get Resynch'd Data
|
|
CHECK(m_pChgIRowset->GetData(m_rghRowsResynched[0], m_hChgAccessor, m_pResynchRowsetData), S_OK);
|
|
}
|
|
else
|
|
{
|
|
hr = m_pChgIRowset->GetData(m_rghRowsResynched[0], m_hChgAccessor, m_pResynchRowsetData);
|
|
if (DB_E_ERRORSOCCURRED == hr || DB_S_ERRORSOCCURRED == hr)
|
|
{
|
|
for (i=0;i<m_cBindings;i++)
|
|
{
|
|
// if( DBSTATUS_S_OK != *(DBSTATUS *)((DWORD)m_pResynchRowsetData + m_rgBindings[i].obStatus) &&
|
|
// DBSTATUS_S_ISNULL != *(DBSTATUS *)((DWORD)m_pResynchRowsetData + m_rgBindings[i].obStatus) &&
|
|
// DBSTATUS_E_UNAVAILABLE != *(DBSTATUS *)((DWORD)m_pResynchRowsetData + m_rgBindings[i].obStatus))
|
|
if (
|
|
DBSTATUS_S_OK != STATUS_BINDING(m_rgBindings[i],m_pResynchRowsetData) &&
|
|
DBSTATUS_S_ISNULL != STATUS_BINDING(m_rgBindings[i],m_pResynchRowsetData) &&
|
|
DBSTATUS_E_UNAVAILABLE != STATUS_BINDING(m_rgBindings[i],m_pResynchRowsetData)
|
|
)
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
}
|
|
fResults = TRUE;
|
|
}
|
|
if (S_OK != hr)
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
}
|
|
|
|
//Now GetVisibleData on the same row
|
|
CHECK(GetLastVisibleData(m_rghRowsResynched[0], m_hChgAccessor, m_pResynchVisibleData,FALSE),S_OK);
|
|
|
|
//no change is made, these should be the same
|
|
COMPARE(CompareBuffer(m_pResynchVisibleData,m_pResynchRowsetData,m_cBindings,m_rgBindings,m_pIMalloc,FALSE,FALSE,COMPARE_ONLY,TRUE),TRUE);
|
|
|
|
//Everything went OK
|
|
fResults = TRUE;
|
|
}
|
|
CLEANUP:
|
|
FreeOutParams();
|
|
|
|
COMPARE(EndTxns(TRUE), TRUE);
|
|
|
|
if (hRow != DB_NULL_HROW)
|
|
m_pChgIRowset->ReleaseRows(1, &hRow, NULL, NULL, NULL);
|
|
|
|
if (fResults)
|
|
return TEST_PASS;
|
|
else
|
|
return TEST_FAIL;
|
|
}
|
|
// }}
|
|
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(40)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc InsertRows with all status DEFAULT
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCPropCanHoldRowsResynch::Variation_40()
|
|
{
|
|
BOOL fResults = FALSE;
|
|
HROW hRow = DB_NULL_HROW;
|
|
ULONG cRowsObtained = 0;
|
|
BOOL fOverWrite = TRUE;
|
|
ULONG i = 0;
|
|
|
|
|
|
if (m_eTI==TI_IRowsetRefreshFALSE)
|
|
{
|
|
fOverWrite=FALSE;
|
|
}
|
|
|
|
//If no provider support for this isolation level, just return pass
|
|
if (!m_fChaos && !m_fReadUncommitted && !m_fReadCommitted &&
|
|
!m_fRepeatableRead && !m_fSerializable)
|
|
{
|
|
odtLog << wszNoProviderSupport << L"ANY" << wszNewLine;
|
|
return TEST_PASS;
|
|
}
|
|
|
|
//Not all drivers allow starting a txn with rowsets
|
|
//open, so release them before starting a txn
|
|
ReleaseResynchObjects();
|
|
|
|
//Set the highest possible isolation level, to make this test interesting
|
|
//since regardless of isolation, we should always see our own change.
|
|
//Note that we only start a txn for this rowset and not the RORowset,
|
|
//since otherwise the RORowset could lock us from changing
|
|
//due to the high isolation level
|
|
CHECK(m_pChgRowset1->m_pITxnLocal->StartTransaction(m_fHighestSupportedIsoLevel, 0, NULL, NULL), S_OK);
|
|
COMPARE(CreateResynchObjects(m_eTI), TRUE);
|
|
|
|
//Insert new row with all DEFAULTS. do not keep the hRow.
|
|
//value shouldn't matter. the function will fill the value part of the
|
|
//buffer with this seed but the function should use defaults instead.
|
|
COMPARE(m_pChgRowset1->Insert(99, &hRow,TRUE), TRUE);
|
|
|
|
//a GetData is useless since it is unknown whether a provider would go to the back end to resoluve the defauts
|
|
|
|
if (m_fStrongIdentity)
|
|
{
|
|
//Now do a ResynchRows(0/NULL) to check what is brought in
|
|
CHECK(ResynchRefresh(DB_NULL_HCHAPTER,0, NULL, fOverWrite,&m_cRowsResynched, &m_rghRowsResynched, &m_rgRowStatus,FALSE),S_OK);
|
|
|
|
if (m_cRowsResynched)
|
|
{
|
|
//Get Resynch'd Data / should have the defualt since Resynch goes to the backend
|
|
CHECK(m_pChgIRowset->GetData(m_rghRowsResynched[0], m_hChgAccessor, m_pResynchRowsetData), S_OK);
|
|
|
|
for (i=0;i<m_cBindings;i++)
|
|
{
|
|
// if(DBSTATUS_S_OK!=*(DBSTATUS *)((DWORD)m_pResynchRowsetData + m_rgBindings[i].obStatus))
|
|
if (
|
|
DBSTATUS_S_OK != STATUS_BINDING(m_rgBindings[i],m_pResynchRowsetData)
|
|
)
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
}
|
|
|
|
//GetVisibleData on the same row
|
|
CHECK(GetLastVisibleData(m_rghRowsResynched[0], m_hChgAccessor, m_pResynchVisibleData,FALSE),S_OK);
|
|
|
|
//no change is made, these should be the same
|
|
COMPARE(CompareBuffer(m_pResynchVisibleData,m_pResynchRowsetData,m_cBindings,m_rgBindings,m_pIMalloc,FALSE,FALSE,COMPARE_ONLY),TRUE);
|
|
|
|
//Everything went OK
|
|
fResults = TRUE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//can't see the new row
|
|
fResults = TRUE;
|
|
}
|
|
CLEANUP:
|
|
FreeOutParams();
|
|
|
|
COMPARE(EndTxns(TRUE), TRUE);
|
|
|
|
if (hRow != DB_NULL_HROW)
|
|
{
|
|
m_pChgIRowset->ReleaseRows(1, &hRow, NULL, NULL, NULL);
|
|
}
|
|
if (fResults)
|
|
return TEST_PASS;
|
|
else
|
|
return TEST_FAIL;
|
|
}
|
|
// }}
|
|
|
|
|
|
|
|
// {{ TCW_TERMINATE_METHOD
|
|
//--------------------------------------------------------------------
|
|
// @mfunc TestCase Termination Routine
|
|
//
|
|
// @rdesc TRUE or FALSE
|
|
//
|
|
BOOL TCPropCanHoldRowsResynch::Terminate()
|
|
{
|
|
// TO DO: Add your own code here
|
|
|
|
// {{ TCW_TERM_BASECLASS_CHECK2
|
|
return(CPropCanHoldRowsResynch::Terminate());
|
|
} // }}
|
|
// }}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_TC_PROTOTYPE(TCPropNoHoldRowsResynch)
|
|
//*-----------------------------------------------------------------------
|
|
//| Test Case: TCPropNoHoldRowsResynch - Rowset without CANHOLDROWS
|
|
//| Created: 06/01/96
|
|
//*-----------------------------------------------------------------------
|
|
|
|
//--------------------------------------------------------------------
|
|
// @mfunc TestCase Initialization Routine
|
|
//
|
|
// @rdesc TRUE or FALSE
|
|
//
|
|
BOOL TCPropNoHoldRowsResynch::Init()
|
|
{
|
|
DBPROPID PropCanHoldRows = DBPROP_CANHOLDROWS;
|
|
DBPROPOPTIONS PropOption = DBPROPOPTIONS_OPTIONAL;
|
|
|
|
if (TEST_SKIPPED==fnInterfaceSupported())
|
|
{
|
|
return TEST_SKIPPED;
|
|
}
|
|
|
|
// {{ TCW_INIT_BASECLASS_CHECK
|
|
if(CResynchRefresh::Init(m_eTI))
|
|
// }}
|
|
{
|
|
//Change the rowsets generated in CResynchRefresh::Init,
|
|
//But only remove CANHOLDROWS, don't add any new props,
|
|
//Make it setifcheap since if we can't set if off, the provider
|
|
//apparently doesn't support removing it with the current
|
|
//properties set, which is OK
|
|
return ChangeProperties(0, NULL, 1, &PropCanHoldRows, &PropOption);
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(1)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc Read Only Rowset without DBPROP_CANHOLDROWS
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCPropNoHoldRowsResynch::Variation_1()
|
|
{
|
|
ReleaseResynchObjects();
|
|
if (!COMPARE(CreateResynchObjects(m_eTI), TRUE))
|
|
{
|
|
return FALSE;
|
|
}
|
|
return TestResynchRefresh(EREADONLY);
|
|
}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(2)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc Changeable Rowset without DBPROP_CANHOLDROWS
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCPropNoHoldRowsResynch::Variation_2()
|
|
{
|
|
ReleaseResynchObjects();
|
|
if (!COMPARE(CreateResynchObjects(m_eTI), TRUE))
|
|
{
|
|
return FALSE;
|
|
}
|
|
return TestResynchRefresh(ECHANGEABLE);
|
|
}
|
|
// }}
|
|
// {{ TCW_TERMINATE_METHOD
|
|
//--------------------------------------------------------------------
|
|
// @mfunc TestCase Termination Routine
|
|
//
|
|
// @rdesc TRUE or FALSE
|
|
//
|
|
BOOL TCPropNoHoldRowsResynch::Terminate()
|
|
{
|
|
|
|
// {{ TCW_TERM_BASECLASS_CHECK2
|
|
return(CResynchRefresh::Terminate());
|
|
} // }}
|
|
// }}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_TC_PROTOTYPE(TCPropBookmarksResynch)
|
|
//*-----------------------------------------------------------------------
|
|
//| Test Case: TCPropBookmarksResynch - Rowset with BOOKMARKS
|
|
//| Created: 06/01/96
|
|
//*-----------------------------------------------------------------------
|
|
|
|
//--------------------------------------------------------------------
|
|
// @mfunc TestCase Initialization Routine
|
|
//
|
|
// @rdesc TRUE or FALSE
|
|
//
|
|
BOOL TCPropBookmarksResynch::Init()
|
|
{
|
|
DBPROP PropBkmks;
|
|
DBPROPID PropCanHoldRows = DBPROP_CANHOLDROWS;
|
|
DBPROPOPTIONS PropOption = DBPROPOPTIONS_OPTIONAL;
|
|
|
|
if (TEST_SKIPPED==fnInterfaceSupported())
|
|
{
|
|
return TEST_SKIPPED;
|
|
}
|
|
|
|
PropBkmks.dwPropertyID = DBPROP_BOOKMARKS;
|
|
PropBkmks.dwOptions = 0;
|
|
PropBkmks.colid = DB_NULLID;
|
|
PropBkmks.vValue.vt = VT_BOOL;
|
|
V_BOOL(&(PropBkmks.vValue)) = VARIANT_TRUE;
|
|
|
|
// {{ TCW_INIT_BASECLASS_CHECK
|
|
if(CResynchRefresh::Init(m_eTI))
|
|
// }}
|
|
{
|
|
//Add bookmark property, remove Can Hold Rows
|
|
return ChangeProperties(1, &PropBkmks, 1, &PropCanHoldRows, &PropOption);
|
|
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(1)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc Read Only Rowset with DBPROP_BOOKMARKS
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCPropBookmarksResynch::Variation_1()
|
|
{
|
|
return TestResynchRefresh(EREADONLY);
|
|
}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(2)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc Changeable Rowset with DBPROP_BOOKMARKS
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCPropBookmarksResynch::Variation_2()
|
|
{
|
|
return TestResynchRefresh(ECHANGEABLE);
|
|
}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_TERMINATE_METHOD
|
|
//--------------------------------------------------------------------
|
|
// @mfunc TestCase Termination Routine
|
|
//
|
|
// @rdesc TRUE or FALSE
|
|
//
|
|
BOOL TCPropBookmarksResynch::Terminate()
|
|
{
|
|
// {{ TCW_TERM_BASECLASS_CHECK2
|
|
return(CResynchRefresh::Terminate());
|
|
} // }}
|
|
// }}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_TC_PROTOTYPE(TCPropDeferredResynch)
|
|
//*-----------------------------------------------------------------------
|
|
//| Test Case: TCPropDeferredResynch - Rowset with CANHOLDROWS and DEFERRED
|
|
//| Created: 06/01/96
|
|
//*-----------------------------------------------------------------------
|
|
|
|
//--------------------------------------------------------------------
|
|
// @mfunc TestCase Initialization Routine
|
|
//
|
|
// @rdesc TRUE or FALSE
|
|
//
|
|
BOOL TCPropDeferredResynch::Init()
|
|
{
|
|
DBPROP PropDeferred;
|
|
|
|
if (TEST_SKIPPED==fnInterfaceSupported())
|
|
{
|
|
return TEST_SKIPPED;
|
|
}
|
|
|
|
PropDeferred.dwPropertyID = DBPROP_DEFERRED;
|
|
PropDeferred.colid = DB_NULLID; //Set for all columns
|
|
PropDeferred.dwOptions = 0;
|
|
PropDeferred.colid = DB_NULLID;
|
|
PropDeferred.vValue.vt = VT_BOOL;
|
|
V_BOOL(&(PropDeferred.vValue)) = VARIANT_TRUE;
|
|
|
|
// {{ TCW_INIT_BASECLASS_CHECK
|
|
if(CResynchRefresh::Init(m_eTI))
|
|
// }}
|
|
{
|
|
//Add deferred property, don't remove anything
|
|
m_fInitPass = ChangeProperties(1, &PropDeferred, 0, NULL, NULL);
|
|
return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(1)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc Read Only Rowset with DBPROP_DEFERRED
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCPropDeferredResynch::Variation_1()
|
|
{
|
|
if (!m_fInitPass)
|
|
{
|
|
//if the init fails it is because the property couldn't not be set, this is not an error
|
|
odtLog << L"DBPROP_DEFERRED not supported" << wszNewLine;
|
|
return TEST_PASS;
|
|
}
|
|
|
|
//Test visible data on our read only rowset -- we don't have
|
|
//an isolation level, so pass CHAOS so it is ignored by this func
|
|
if (GenerateResynchData(m_pRORowset1, ISOLATIONLEVEL_CHAOS, m_hChgAccessor))
|
|
{
|
|
if (VerifyData(VERIFY_NEW,VERIFY_NEW, VERIFY_OLD, VERIFY_NEW))
|
|
{
|
|
FreeOutParams();
|
|
return TEST_PASS;
|
|
}
|
|
FreeOutParams();
|
|
}
|
|
return TEST_FAIL;
|
|
}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(2)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc Changeable Rowset with DBPROP_DEFERRED
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCPropDeferredResynch::Variation_2()
|
|
{
|
|
if (!m_fInitPass)
|
|
{
|
|
//if the init fails it is because the property couldn't not be set, this is not an error
|
|
odtLog << L"DBPROP_DEFERRED not supported" << wszNewLine;
|
|
return TEST_PASS;
|
|
}
|
|
//Test visible data on our changeable rowset -- we don't have
|
|
//an isolation level, so pass CHAOS so it is ignored by this func
|
|
if (GenerateResynchData(m_pChgRowset1, ISOLATIONLEVEL_CHAOS, m_hChgAccessor))
|
|
{
|
|
if (VerifyData(VERIFY_NEW,VERIFY_NEW, VERIFY_OLD, VERIFY_NEW))
|
|
{
|
|
FreeOutParams();
|
|
return TEST_PASS;
|
|
}
|
|
FreeOutParams();
|
|
}
|
|
return TEST_FAIL;
|
|
}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_TERMINATE_METHOD
|
|
//--------------------------------------------------------------------
|
|
// @mfunc TestCase Termination Routine
|
|
//
|
|
// @rdesc TRUE or FALSE
|
|
//
|
|
BOOL TCPropDeferredResynch::Terminate()
|
|
{
|
|
// TO DO: Add your own code here
|
|
|
|
// {{ TCW_TERM_BASECLASS_CHECK2
|
|
return(CResynchRefresh::Terminate());
|
|
} // }}
|
|
// }}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_TC_PROTOTYPE(TCPropCacheDeferredResynch)
|
|
//*-----------------------------------------------------------------------
|
|
//| Test Case: TCPropCacheDeferredResynch - Rowset with CACHEDEFERRED
|
|
//| Created: 06/02/96
|
|
//*-----------------------------------------------------------------------
|
|
|
|
//--------------------------------------------------------------------
|
|
// @mfunc TestCase Initialization Routine
|
|
//
|
|
// @rdesc TRUE or FALSE
|
|
//
|
|
BOOL TCPropCacheDeferredResynch::Init()
|
|
{
|
|
DBPROP CacheDeferredProp;
|
|
|
|
if (TEST_SKIPPED==fnInterfaceSupported())
|
|
{
|
|
return TEST_SKIPPED;
|
|
}
|
|
|
|
//CacheDeferred automatically implies deferred
|
|
CacheDeferredProp.dwPropertyID = DBPROP_CACHEDEFERRED;
|
|
CacheDeferredProp.colid = DB_NULLID; //Set for all columns
|
|
CacheDeferredProp.dwOptions = 0;
|
|
CacheDeferredProp.colid = DB_NULLID;
|
|
CacheDeferredProp.vValue.vt = VT_BOOL;
|
|
V_BOOL(&(CacheDeferredProp.vValue)) = VARIANT_TRUE;
|
|
|
|
// {{ TCW_INIT_BASECLASS_CHECK
|
|
if(CResynchRefresh::Init(m_eTI))
|
|
// }}
|
|
{
|
|
//Add deferred and cache deferred properties, don't remove anything
|
|
m_fInitPass = ChangeProperties(1, &CacheDeferredProp, 0, NULL, NULL);
|
|
return TRUE;
|
|
}
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(1)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc Read Only Rowset with DBPROP_CACHEDEFERRED
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCPropCacheDeferredResynch::Variation_1()
|
|
{
|
|
if (!m_fInitPass)
|
|
{
|
|
//if the init fails it is because the property couldn't not be set, this is not an error
|
|
odtLog << L"DBPROP_CACHEDEFERRED not supported" << wszNewLine;
|
|
return TEST_PASS;
|
|
}
|
|
//Cause some new visible data and retrieve it -- it should be cached
|
|
if (GenerateResynchData(m_pRORowset1, ISOLATIONLEVEL_CHAOS, m_hROAccessor))
|
|
{
|
|
if (VerifyData(VERIFY_NEW,VERIFY_NEW, VERIFY_OLD, VERIFY_NEW))
|
|
{
|
|
//Resynch again should rewrite cached values, so try it once more
|
|
if (GenerateResynchData(m_pRORowset1, ISOLATIONLEVEL_CHAOS, m_hROAccessor))
|
|
{
|
|
//Should see new stuff
|
|
if (VerifyData(VERIFY_NEW,VERIFY_NEW, VERIFY_OLD, VERIFY_NEW))
|
|
{
|
|
FreeOutParams();
|
|
return TEST_PASS;
|
|
}
|
|
}
|
|
}
|
|
FreeOutParams();
|
|
}
|
|
return TEST_FAIL;
|
|
}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(2)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc Changeable Rowset with DBPROP_CACHEDEFERRED
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCPropCacheDeferredResynch::Variation_2()
|
|
{
|
|
if (!m_fInitPass)
|
|
{
|
|
//if the init fails it is because the property couldn't not be set, this is not an error
|
|
odtLog << L"DBPROP_CACHEDEFERRED not supported" << wszNewLine;
|
|
return TEST_PASS;
|
|
}
|
|
//Cause some new visible data and retrieve it -- it should be cached
|
|
if (GenerateResynchData(m_pChgRowset1, ISOLATIONLEVEL_CHAOS, m_hChgAccessor))
|
|
{
|
|
if (VerifyData(VERIFY_NEW,VERIFY_NEW, VERIFY_OLD, VERIFY_NEW))
|
|
{
|
|
//Resynch again should rewrite cached values, so try it once more
|
|
if (GenerateResynchData(m_pChgRowset1, ISOLATIONLEVEL_CHAOS, m_hChgAccessor))
|
|
{
|
|
//Should see new stuff
|
|
if (VerifyData(VERIFY_NEW,VERIFY_NEW, VERIFY_OLD, VERIFY_NEW))
|
|
{
|
|
FreeOutParams();
|
|
return TEST_PASS;
|
|
}
|
|
}
|
|
}
|
|
FreeOutParams();
|
|
}
|
|
return TEST_FAIL;
|
|
}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_TERMINATE_METHOD
|
|
//--------------------------------------------------------------------
|
|
// @mfunc TestCase Termination Routine
|
|
//
|
|
// @rdesc TRUE or FALSE
|
|
//
|
|
BOOL TCPropCacheDeferredResynch::Terminate()
|
|
{
|
|
// TO DO: Add your own code here
|
|
|
|
// {{ TCW_TERM_BASECLASS_CHECK2
|
|
return(CResynchRefresh::Terminate());
|
|
} // }}
|
|
// }}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_TC_PROTOTYPE(TCPropUpdateResynch)
|
|
//*-----------------------------------------------------------------------
|
|
//| Test Case: TCPropUpdateResynch - Rowset with IRowsetUpdate
|
|
//| Created: 06/02/96
|
|
//*-----------------------------------------------------------------------
|
|
|
|
|
|
//--------------------------------------------------------------------
|
|
// @mfunc TestCase Initialization Routine
|
|
//
|
|
// @rdesc TRUE or FALSE
|
|
//
|
|
BOOL TCPropUpdateResynch::Init()
|
|
{
|
|
DBPROP UpdateProp[2];
|
|
|
|
m_pChgIRowsetUpdate1 = NULL;
|
|
m_pChgIRowsetUpdate2 = NULL;
|
|
|
|
if (TEST_SKIPPED==fnInterfaceSupported())
|
|
{
|
|
return TEST_SKIPPED;
|
|
}
|
|
|
|
UpdateProp[0].dwPropertyID = DBPROP_IRowsetChange;
|
|
UpdateProp[0].dwOptions = 0;
|
|
UpdateProp[0].colid = DB_NULLID;
|
|
UpdateProp[0].vValue.vt = VT_BOOL;
|
|
V_BOOL(&(UpdateProp[0].vValue)) = VARIANT_TRUE;
|
|
|
|
UpdateProp[1].dwPropertyID = DBPROP_IRowsetUpdate;
|
|
UpdateProp[1].dwOptions = 0;
|
|
UpdateProp[1].colid = DB_NULLID;
|
|
UpdateProp[1].vValue.vt = VT_BOOL;
|
|
V_BOOL(&(UpdateProp[1].vValue)) = VARIANT_TRUE;
|
|
|
|
// {{ TCW_INIT_BASECLASS_CHECK
|
|
if(CResynchRefresh::Init(m_eTI))
|
|
// }}
|
|
{
|
|
//Add IRowsetUpdate and don't remove anything
|
|
if (ChangeProperties(2, UpdateProp, 0, NULL, NULL))
|
|
{
|
|
//If properties were set OK, we know IRowsetUpdate is supported
|
|
if (VerifyInterface(m_pChgRowset1->m_pIAccessor, IID_IRowsetUpdate,ROWSET_INTERFACE, (IUnknown **)&m_pChgIRowsetUpdate1))
|
|
{
|
|
if (VerifyInterface(m_pChgRowset2->m_pIAccessor, IID_IRowsetUpdate,ROWSET_INTERFACE, (IUnknown **)&m_pChgIRowsetUpdate2))
|
|
{
|
|
return TRUE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(1)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc Soft deleted row
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCPropUpdateResynch::Variation_1()
|
|
{
|
|
HROW hRow = DB_NULL_HROW;
|
|
HROW hRowChanged = DB_NULL_HROW;
|
|
IRowsetChange *pIRowsetChange = NULL;
|
|
BOOL fResults = FALSE;
|
|
DBROWSTATUS PendingStatus;
|
|
BOOL fOverWrite = TRUE;
|
|
|
|
if (m_eTI==TI_IRowsetRefreshFALSE)
|
|
{
|
|
fOverWrite=FALSE;
|
|
}
|
|
|
|
//If delete isn't supported this variation isn't applicable
|
|
if (!VerifyInterface(m_pChgRowset1->m_pIAccessor, IID_IRowsetChange,
|
|
ROWSET_INTERFACE, (IUnknown **)&pIRowsetChange))
|
|
{
|
|
return TEST_SKIPPED;
|
|
}
|
|
if (ChangeUnderlyingRowAndGetHrow(m_pChgRowset1, ISOLATIONLEVEL_CHAOS, &hRow))
|
|
{
|
|
//Make permanent our update
|
|
if (CHECK(m_pChgIRowsetUpdate2->Update(NULL, 0, NULL, NULL, NULL, NULL), S_OK))
|
|
{
|
|
//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
|
|
}
|
|
//Soft delete the row we changed on second txn
|
|
if (CHECK(pIRowsetChange->DeleteRows(NULL, 1, &hRow, NULL), S_OK))
|
|
{
|
|
if (CHECK(ResynchRefresh(DB_NULL_HCHAPTER,0, NULL, fOverWrite, &m_cRowsResynched,&m_rghRowsResynched, &m_rgRowStatus,FALSE), DB_E_ERRORSOCCURRED))
|
|
{
|
|
COMPARE(m_cRowsResynched,1);
|
|
COMPARE(m_rghRowsResynched[0],hRow);
|
|
if (!COMPARE(m_rgRowStatus[0], DBROWSTATUS_E_DELETED))
|
|
{
|
|
fResults=TEST_FAIL;
|
|
goto CLEANUP;
|
|
}
|
|
|
|
//Now try resynch methods on soft deleted row
|
|
if (GetDataBuffers(m_pChgRowset1, ISOLATIONLEVEL_CHAOS, m_hChgAccessor, hRow))
|
|
{
|
|
if (g_fDeletedRow || g_fBlobFail)
|
|
{
|
|
//if this is true then hRow now points to a deleted row
|
|
//buffers can not be filled from a deleted row
|
|
//or
|
|
//a BLOB column was in a row that was inserted and some providers have a hard time handling
|
|
//BLOBs so they don't
|
|
fResults=TRUE;
|
|
goto CLEANUP;
|
|
}
|
|
//Status should now be Unchanged since we resynch'd
|
|
//and brought the deleted row back again
|
|
if (CHECK(m_pChgIRowsetUpdate1->GetRowStatus(NULL, 1, &hRow, &PendingStatus), S_OK))
|
|
{
|
|
if (COMPARE(PendingStatus, DBPENDINGSTATUS_UNCHANGED))
|
|
{
|
|
//and everything should be the same as for a normal row
|
|
if (VerifyData(VERIFY_NEW, VERIFY_NEW, VERIFY_OLD, VERIFY_NEW))
|
|
{
|
|
fResults = TRUE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
CLEANUP:
|
|
//clean up any left over pending changes
|
|
m_pChgIRowsetUpdate1->Undo(NULL,0,NULL,NULL,NULL,NULL);
|
|
m_pChgIRowsetUpdate2->Undo(NULL,0,NULL,NULL,NULL,NULL);
|
|
|
|
FreeOutParams();
|
|
if (hRow != DB_NULL_HROW)
|
|
m_pChgIRowset->ReleaseRows(1, &hRow, NULL, NULL, NULL);
|
|
if (pIRowsetChange)
|
|
{
|
|
pIRowsetChange->Release();
|
|
pIRowsetChange=NULL;
|
|
}
|
|
return fResults;
|
|
}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(2)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc Soft inserted row
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCPropUpdateResynch::Variation_2()
|
|
{
|
|
HROW hRow = DB_NULL_HROW;
|
|
BOOL fResults = FALSE;
|
|
DBROWSTATUS PendingStatus;
|
|
BOOL fOverWrite = TRUE;
|
|
|
|
if (m_eTI==TI_IRowsetRefreshFALSE)
|
|
{
|
|
fOverWrite=FALSE;
|
|
}
|
|
|
|
if (m_pChgRowset1->Insert(GetNextRowToInsert(), &hRow))
|
|
{
|
|
m_cRowsResynched = 5;
|
|
m_rghRowsResynched = (HROW *)JUNK_PTR;
|
|
m_rgRowStatus = (DBROWSTATUS *)JUNK_PTR;
|
|
//Now do a ResynchRows, again this should be considered pending insert error
|
|
if (CHECK(ResynchRefresh(DB_NULL_HCHAPTER,1, &hRow, fOverWrite, &m_cRowsResynched, &m_rghRowsResynched, &m_rgRowStatus, FALSE), DB_E_ERRORSOCCURRED))
|
|
{
|
|
COMPARE(m_cRowsResynched,1);
|
|
COMPARE(m_rghRowsResynched[0],hRow);
|
|
CompareOutParams(1, &hRow);
|
|
|
|
if (COMPARE(m_rgRowStatus[0], DBROWSTATUS_E_PENDINGINSERT))
|
|
{
|
|
if (CHECK(m_pChgIRowsetUpdate1->GetRowStatus(NULL, 1, &hRow,&PendingStatus), S_OK))
|
|
{
|
|
if (COMPARE(PendingStatus, DBPENDINGSTATUS_NEW))
|
|
{
|
|
//Now try resynch methods on soft inserted row.
|
|
//Soft insert has no row on server, should be considered an error
|
|
if (CHECK(GetLastVisibleData(hRow, m_hChgAccessor,m_pVisibleData,FALSE), DB_E_PENDINGINSERT))
|
|
{
|
|
//Next GetData from cache, this may return DB_S_ERRORSOCCURRED if
|
|
//their are columns which the server has to update to complete the row
|
|
if (SUCCEEDED(m_pChgIRowset->GetData(hRow, m_hChgAccessor, m_pRowsetData)))
|
|
{
|
|
fResults = TRUE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
FreeOutParams();
|
|
}
|
|
}
|
|
}
|
|
//clean up any left over pending changes
|
|
m_pChgIRowsetUpdate1->Undo(NULL,0,NULL,NULL,NULL,NULL);
|
|
m_pChgIRowsetUpdate2->Undo(NULL,0,NULL,NULL,NULL,NULL);
|
|
|
|
if (hRow != DB_NULL_HROW)
|
|
{
|
|
m_pChgIRowset->ReleaseRows(1, &hRow, NULL, NULL, NULL);
|
|
}
|
|
if (fResults)
|
|
return TEST_PASS;
|
|
else
|
|
return TEST_FAIL;
|
|
}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(3)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc Soft changed row
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCPropUpdateResynch::Variation_3()
|
|
{
|
|
HROW hRow = DB_NULL_HROW;
|
|
HROW hRowChanged = DB_NULL_HROW;
|
|
BOOL fResults = FALSE;
|
|
DBROWSTATUS PendingStatus;
|
|
BOOL fOverWrite = TRUE;
|
|
|
|
if (m_eTI==TI_IRowsetRefreshFALSE)
|
|
{
|
|
fOverWrite=FALSE;
|
|
}
|
|
|
|
//Change a row from underneath but keep the handle to
|
|
//the old value still in the rowset cache
|
|
if (ChangeUnderlyingRowAndGetHrow(m_pChgRowset1,ISOLATIONLEVEL_CHAOS, &hRow))//change 1 into 16 on the backend
|
|
{
|
|
//Make permanent our update
|
|
if (CHECK(m_pChgIRowsetUpdate2->Update(NULL, 0, NULL, NULL, NULL, NULL), S_OK))
|
|
{
|
|
//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 change the row in the current rowset cache which has already been
|
|
//changed on the server. Use a new insert value that doesn't exist
|
|
//in the row cache or on the server. Note we are in delayed mode so
|
|
//this change will never propagate to the server and GetNextRowToInsert count
|
|
//won't increment.
|
|
//We already have the hRow, so don't bother to keep another handle to it
|
|
if (m_pChgRowset1->Change((GetNextRowToDelete()-1), GetNextRowToInsert(), NULL))//change 1 into 17
|
|
{
|
|
//Now try resynch methods on soft change row
|
|
if (GetDataBuffers(m_pChgRowset1, ISOLATIONLEVEL_CHAOS, m_hChgAccessor, hRow))
|
|
{
|
|
//if there is a visual cache lets see the change from rowset1.
|
|
if (g_fVisualCache && (m_eTI!=TI_IRowsetResynch))
|
|
{
|
|
//GetLastVsibleData does not overwrtie the visual cache
|
|
fResults = COMPARE(CompareData(m_pChgRowset1->m_pTable->CountColumnsOnTable(),
|
|
m_pChgRowset1->m_rgTableColOrds, (GetNextRowToDelete()-1),
|
|
m_pVisibleData, m_cBindings, m_rgBindings, m_pChgRowset1->m_pTable,
|
|
m_pIMalloc, PRIMARY, COMPARE_ONLY), TRUE);
|
|
//the rowset buffer will have this rowset's change
|
|
fResults = COMPARE(CompareData(m_pChgRowset1->m_pTable->CountColumnsOnTable(),
|
|
m_pChgRowset1->m_rgTableColOrds, GetNextRowToInsert(),
|
|
m_pRowsetData, m_cBindings, m_rgBindings, m_pChgRowset1->m_pTable,
|
|
m_pIMalloc, PRIMARY, COMPARE_ONLY), TRUE);
|
|
}
|
|
//if this is true then hRow now points to a deleted row
|
|
//buffers can not be filled from a deleted row
|
|
if (g_fDeletedRow)
|
|
{
|
|
fResults=TRUE;
|
|
goto CLEANUP;
|
|
}
|
|
//if there is no visual cache lets see the change from rowset 2 from GetXVisibleData
|
|
if (!g_fVisualCache)
|
|
{
|
|
//Visible data should be the new stuff as well
|
|
fResults = COMPARE(CompareData(m_pChgRowset1->m_pTable->CountColumnsOnTable(),
|
|
m_pChgRowset1->m_rgTableColOrds, (GetNextRowToInsert()-1),
|
|
m_pVisibleData, m_cBindings, m_rgBindings, m_pChgRowset1->m_pTable,
|
|
m_pIMalloc, PRIMARY, COMPARE_ONLY), TRUE);
|
|
}
|
|
|
|
//Status should be unchanged since we resynch'd it (even
|
|
//though data changed)
|
|
if (CHECK(m_pChgIRowsetUpdate1->GetRowStatus(NULL, 1, &hRow, &PendingStatus), S_OK))
|
|
{
|
|
if (COMPARE(PendingStatus, DBPENDINGSTATUS_UNCHANGED))
|
|
{
|
|
if (fOverWrite)
|
|
{
|
|
//Refresh TRUE should get new values.
|
|
fResults = COMPARE(CompareData(m_pChgRowset1->m_pTable->CountColumnsOnTable(),
|
|
m_pChgRowset1->m_rgTableColOrds, (GetNextRowToInsert()-1), m_pResynchRowsetData,
|
|
m_cBindings, m_rgBindings, m_pChgRowset1->m_pTable,
|
|
m_pIMalloc, PRIMARY, COMPARE_ONLY), TRUE);
|
|
}
|
|
else
|
|
{
|
|
//Resynching should move everything to the new values.
|
|
//Note we don't check the buffer m_pRowsetData which just
|
|
//contains the values we set before calling resynch. This
|
|
//scenario is tested in Update.
|
|
fResults = COMPARE(CompareData(m_pChgRowset1->m_pTable->CountColumnsOnTable(),
|
|
m_pChgRowset1->m_rgTableColOrds, (GetNextRowToInsert()), m_pResynchRowsetData,
|
|
m_cBindings, m_rgBindings, m_pChgRowset1->m_pTable,
|
|
m_pIMalloc, PRIMARY, COMPARE_ONLY), TRUE);
|
|
}
|
|
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
CLEANUP:
|
|
//clean up any left over pending changes
|
|
m_pChgIRowsetUpdate1->Undo(NULL,0,NULL,NULL,NULL,NULL);
|
|
m_pChgIRowsetUpdate2->Undo(NULL,0,NULL,NULL,NULL,NULL);
|
|
|
|
FreeOutParams();
|
|
if (hRow != DB_NULL_HROW)
|
|
m_pChgIRowset->ReleaseRows(1, &hRow, NULL, NULL, NULL);
|
|
|
|
if (fResults)
|
|
return TEST_PASS;
|
|
else
|
|
return TEST_FAIL;
|
|
}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(4)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc Inserted row after Update
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCPropUpdateResynch::Variation_4()
|
|
{
|
|
HROW hRow = DB_NULL_HROW;
|
|
BOOL fResults = TEST_FAIL;
|
|
DBROWSTATUS PendingStatus;
|
|
BOOL fOverWrite = TRUE;
|
|
|
|
if (m_eTI==TI_IRowsetRefreshFALSE)
|
|
{
|
|
fOverWrite=FALSE;
|
|
}
|
|
|
|
//Soft insert the row
|
|
if (m_pChgRowset1->Insert(GetNextRowToInsert(), &hRow))
|
|
{
|
|
//Update the row to make it permanent
|
|
if (CHECK(m_pChgIRowsetUpdate1->Update(NULL, 1, &hRow, NULL, NULL, NULL), S_OK))
|
|
{
|
|
//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
|
|
}
|
|
//Record that we just updated
|
|
g_InsertIncrement();
|
|
|
|
m_cRowsResynched = 5;
|
|
m_rghRowsResynched = (HROW *)JUNK_PTR;
|
|
m_rgRowStatus = (DBROWSTATUS *)JUNK_PTR;
|
|
//Now try resynch methods on inserted row -- this fails if we don't
|
|
//have strong identity support
|
|
if (!m_fStrongIdentity)
|
|
{
|
|
//Now do a ResynchRows, this should be considered an error
|
|
if (CHECK(ResynchRefresh(DB_NULL_HCHAPTER,1, &hRow, fOverWrite,&m_cRowsResynched, &m_rghRowsResynched, &m_rgRowStatus,FALSE), DB_E_ERRORSOCCURRED))
|
|
{
|
|
COMPARE(m_cRowsResynched,1);
|
|
COMPARE(m_rghRowsResynched[0],hRow);
|
|
CompareOutParams(1, &hRow);
|
|
|
|
if (COMPARE(m_rgRowStatus[0], DBROWSTATUS_E_NEWLYINSERTED))
|
|
{
|
|
if (CHECK(m_pChgIRowsetUpdate1->GetRowStatus(NULL, 1, &hRow, &PendingStatus), S_OK))
|
|
{
|
|
if (COMPARE(PendingStatus, DBPENDINGSTATUS_UNCHANGED))
|
|
{
|
|
if (CHECK(GetLastVisibleData(hRow, m_hChgAccessor, m_pVisibleData,FALSE), DB_E_NEWLYINSERTED))
|
|
{
|
|
fResults = TRUE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
FreeOutParams();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//Now do a ResynchRows
|
|
if (CHECK(ResynchRefresh(DB_NULL_HCHAPTER,1, &hRow, fOverWrite,&m_cRowsResynched, &m_rghRowsResynched, &m_rgRowStatus,FALSE), S_OK))
|
|
{
|
|
COMPARE(m_cRowsResynched,1);
|
|
COMPARE(m_rghRowsResynched[0],hRow);
|
|
CompareOutParams(1, &hRow);
|
|
|
|
if (COMPARE(m_rgRowStatus[0], DBROWSTATUS_S_OK))
|
|
{
|
|
if (CHECK(m_pChgIRowsetUpdate1->GetRowStatus(NULL, 1, &hRow, &PendingStatus), S_OK))
|
|
{
|
|
if (COMPARE(PendingStatus, DBPENDINGSTATUS_UNCHANGED))
|
|
{
|
|
if (CHECK(GetLastVisibleData(hRow, m_hChgAccessor, m_pVisibleData,FALSE), S_OK))
|
|
{
|
|
//Visible data should be the new stuffeData,pCompareData,m_cBindings,m_rgBindings,m_pIMalloc,FALSE,FALSE,COMPARE_ONLY),TRUE) &&
|
|
fResults = COMPARE(CompareData(m_pChgRowset1->m_pTable->CountColumnsOnTable(),
|
|
m_pChgRowset1->m_rgTableColOrds, (GetNextRowToInsert()-1),
|
|
m_pVisibleData, m_cBindings, m_rgBindings, m_pChgRowset1->m_pTable,
|
|
m_pIMalloc, PRIMARY, COMPARE_ONLY), TRUE);
|
|
|
|
fResults = TRUE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
FreeOutParams();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
//clean up any left over pending changes
|
|
m_pChgIRowsetUpdate1->Undo(NULL,0,NULL,NULL,NULL,NULL);
|
|
m_pChgIRowsetUpdate2->Undo(NULL,0,NULL,NULL,NULL,NULL);
|
|
|
|
if (hRow != DB_NULL_HROW)
|
|
{
|
|
m_pChgIRowset->ReleaseRows(1, &hRow, NULL, NULL, NULL);
|
|
}
|
|
if (fResults)
|
|
{
|
|
return TEST_PASS;
|
|
}
|
|
else
|
|
{
|
|
return TEST_FAIL;
|
|
}
|
|
}
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(5)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc Pending change
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCPropUpdateResynch::Variation_5()
|
|
{
|
|
HROW hRow = DB_NULL_HROW;
|
|
BOOL fResults = TEST_FAIL;
|
|
DBPENDINGSTATUS PendingRowStatus = (DBPENDINGSTATUS)JUNK_PTR;
|
|
DBPENDINGSTATUS *rgPendingRow = NULL;
|
|
DBPENDINGSTATUS PendingStatusReq = DBPENDINGSTATUS_NEW | DBPENDINGSTATUS_CHANGED | DBPENDINGSTATUS_DELETED;
|
|
DBCOUNTITEM uPRows = 0;
|
|
HROW *rghPRow = NULL;
|
|
BOOL fOverWrite = TRUE;
|
|
BYTE *pPendingData = NULL;
|
|
BYTE *pCacheData = NULL;
|
|
|
|
|
|
pPendingData = (BYTE *)PROVIDER_ALLOC(m_cbRowSize);
|
|
memset(pPendingData, 0, (size_t)m_cbRowSize);
|
|
pCacheData = (BYTE *)PROVIDER_ALLOC(m_cbRowSize);
|
|
memset(pCacheData, 0, (size_t)m_cbRowSize);
|
|
|
|
if (m_eTI==TI_IRowsetRefreshFALSE)
|
|
{
|
|
fOverWrite=FALSE;
|
|
}
|
|
|
|
//(Pending) Change a row ourselves and keep hRow
|
|
COMPARE(m_pChgRowset1->Change(GetNextRowToDelete(), GetNextRowToInsert(), &hRow), TRUE);
|
|
|
|
//get Pending data
|
|
CHECK(m_pChgIRowset->GetData(hRow, m_hChgAccessor, pPendingData),S_OK);
|
|
|
|
//Now do a ResynchRows
|
|
CHECK(ResynchRefresh(DB_NULL_HCHAPTER,1, &hRow, fOverWrite, &m_cRowsResynched, &m_rghRowsResynched, &m_rgRowStatus, FALSE), S_OK);
|
|
|
|
//if overwrite is true then this is Resync or fOverwrite in Refresh is TRUE
|
|
//so there will be no pending status or pending rows
|
|
if (fOverWrite)
|
|
{
|
|
CHECK(m_pChgIRowsetUpdate1->GetRowStatus(NULL, 1, &hRow, &PendingRowStatus), S_OK);
|
|
|
|
//overwrite knocked off anything pending
|
|
COMPARE(DBPENDINGSTATUS_UNCHANGED,PendingRowStatus);
|
|
|
|
CHECK(m_pChgIRowsetUpdate1->GetPendingRows(NULL, PendingStatusReq, &uPRows, &rghPRow, &rgPendingRow), S_FALSE);
|
|
|
|
COMPARE(0,uPRows);
|
|
fResults = TEST_PASS;
|
|
}
|
|
//if fOverwrite is false there should be pending rows and pending row status
|
|
else
|
|
{
|
|
CHECK(m_pChgIRowsetUpdate1->GetRowStatus(NULL, 1, &hRow, &PendingRowStatus), S_OK);
|
|
|
|
//should still be pending
|
|
COMPARE(DBPENDINGSTATUS_CHANGED,PendingRowStatus);
|
|
|
|
//leaves the pending row
|
|
CHECK(m_pChgIRowsetUpdate1->GetPendingRows(NULL, PendingStatusReq, &uPRows, &rghPRow, &rgPendingRow), S_OK);
|
|
|
|
COMPARE(DBPENDINGSTATUS_CHANGED,rgPendingRow[0]);
|
|
|
|
COMPARE(1,uPRows);
|
|
|
|
//call update to xmit the changed row
|
|
CHECK(m_pChgIRowsetUpdate1->Update(NULL, 1, &hRow, NULL, NULL, NULL), S_OK);
|
|
|
|
g_DeleteAndInsertIncrement();
|
|
FreeOutParams();
|
|
|
|
//call resynch/refresh again to make sure the changed row made it to the back end
|
|
//Now do a ResynchRows
|
|
CHECK(ResynchRefresh(DB_NULL_HCHAPTER,1, &hRow, fOverWrite, &m_cRowsResynched, &m_rghRowsResynched, &m_rgRowStatus, FALSE), S_OK);
|
|
|
|
//get resynched data
|
|
CHECK(m_pChgIRowset->GetData(hRow, m_hChgAccessor, pCacheData),S_OK);
|
|
|
|
//compare the data just read from the back end with the pending data, we should see the change
|
|
COMPARE(CompareBuffer(pCacheData,pPendingData,m_cBindings,m_rgBindings,m_pIMalloc,FALSE,FALSE,COMPARE_ONLY),TRUE);
|
|
|
|
fResults = TEST_PASS;
|
|
FreeOutParams();
|
|
}
|
|
|
|
if (hRow != DB_NULL_HROW)
|
|
{
|
|
m_pChgIRowset->ReleaseRows(1, &hRow, NULL, NULL, NULL);
|
|
}
|
|
|
|
FreeOutParams();
|
|
|
|
//clean up any left over pending changes
|
|
m_pChgIRowsetUpdate1->Undo(NULL,0,NULL,NULL,NULL,NULL);
|
|
m_pChgIRowsetUpdate2->Undo(NULL,0,NULL,NULL,NULL,NULL);
|
|
|
|
PROVIDER_FREE(pPendingData);
|
|
PROVIDER_FREE(pCacheData);
|
|
PROVIDER_FREE(rghPRow);
|
|
PROVIDER_FREE(rgPendingRow);
|
|
if (fResults)
|
|
{
|
|
return TEST_PASS;
|
|
}
|
|
else
|
|
{
|
|
return TEST_FAIL;
|
|
}
|
|
}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(6)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc GetOriginalData
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCPropUpdateResynch::Variation_6()
|
|
{
|
|
HROW hRow = DB_NULL_HROW;
|
|
BOOL fResults = TEST_FAIL;
|
|
DBPENDINGSTATUS PendingRowStatus = (DBPENDINGSTATUS)JUNK_PTR;
|
|
DBPENDINGSTATUS *rgPendingRow = NULL;
|
|
DBPENDINGSTATUS PendingStatusReq = DBPENDINGSTATUS_NEW | DBPENDINGSTATUS_CHANGED | DBPENDINGSTATUS_DELETED;
|
|
ULONG uPRows = 0;
|
|
HROW *rghPRow = NULL;
|
|
BOOL fOverWrite = TRUE;
|
|
//data
|
|
BYTE *pOriginalData = NULL;
|
|
BYTE *pResynchData = NULL;
|
|
BYTE *pPendingData = NULL;
|
|
BYTE *pVisibleData = NULL;
|
|
BYTE *pCacheData1 = NULL;
|
|
HRESULT hr;
|
|
|
|
|
|
pOriginalData = (BYTE *)PROVIDER_ALLOC(m_cbRowSize);
|
|
memset(pOriginalData, 0, (size_t)m_cbRowSize);
|
|
pResynchData = (BYTE *)PROVIDER_ALLOC(m_cbRowSize);
|
|
memset(pResynchData, 0, (size_t)m_cbRowSize);
|
|
pPendingData = (BYTE *)PROVIDER_ALLOC(m_cbRowSize);
|
|
memset(pPendingData, 0, (size_t)m_cbRowSize);
|
|
pVisibleData = (BYTE *)PROVIDER_ALLOC(m_cbRowSize);
|
|
memset(pVisibleData, 0, (size_t)m_cbRowSize);
|
|
pCacheData1 = (BYTE *)PROVIDER_ALLOC(m_cbRowSize);
|
|
memset(pCacheData1, 0, (size_t)m_cbRowSize);
|
|
|
|
g_fDeletedRow = FALSE;
|
|
|
|
if (m_eTI==TI_IRowsetRefreshFALSE)
|
|
{
|
|
fOverWrite=FALSE;
|
|
}
|
|
|
|
//Change a row from underneath but keep the handle to
|
|
//the old value still in the rowset cache
|
|
if (ChangeUnderlyingRowAndGetHrow(m_pChgRowset1,ISOLATIONLEVEL_CHAOS, &hRow))
|
|
{
|
|
//get cache'd data off 1
|
|
CHECK(m_pChgIRowset->GetData(hRow, m_hChgAccessor, pCacheData1),S_OK);
|
|
|
|
//Make permanent our update from underneath
|
|
CHECK(m_pChgIRowsetUpdate2->Update(NULL, 0, NULL, NULL, NULL, NULL), S_OK);
|
|
|
|
//Now change the row in the current rowset cache which has already been
|
|
//changed on the server. Use a new insert value that doesn't exist
|
|
//in the row cache or on the server. Note we are in delayed mode so
|
|
//this change will never propagate to the server and GetNextRowToInsert count
|
|
//won't increment.
|
|
//We already have the hRow, so don't bother to keep another handle to it
|
|
if (m_pChgRowset1->Change((GetNextRowToDelete()-1), GetNextRowToInsert(), NULL))
|
|
{
|
|
//get pending data
|
|
m_pChgIRowset->GetData(hRow, m_hChgAccessor, pPendingData);
|
|
|
|
m_cRowsResynched = 5;
|
|
m_rghRowsResynched = (HROW *)JUNK_PTR;
|
|
m_rgRowStatus = (DBROWSTATUS *)JUNK_PTR;
|
|
//Now do a ResynchRows
|
|
hr = ResynchRefresh(DB_NULL_HCHAPTER,1, &hRow, fOverWrite, &m_cRowsResynched, &m_rghRowsResynched, &m_rgRowStatus, FALSE);
|
|
|
|
if (hr!=S_OK)
|
|
{
|
|
//account for the fact that some providers might delete/insert a row when asked to change it
|
|
//this may put a hole in the rowset and put the newrow somewhere else in the rowset (most likley at the end of the rowset)
|
|
if (DB_E_ERRORSOCCURRED==hr)
|
|
{
|
|
COMPARE(m_cRowsResynched,1);
|
|
COMPARE(m_rghRowsResynched[0],hRow);
|
|
COMPARE(DBROWSTATUS_E_DELETED,m_rgRowStatus[0]);
|
|
g_fDeletedRow = TRUE;
|
|
}
|
|
else
|
|
{
|
|
FreeOutParams();
|
|
goto CLEANUP;
|
|
}
|
|
}
|
|
FreeOutParams();
|
|
|
|
//get resynch'd data
|
|
//for optimazation reasons, as long as this doesn't GPF practially anything can be returned here.
|
|
m_pChgIRowset->GetData(hRow, m_hChgAccessor, pResynchData);
|
|
|
|
//if this is resynch or there is no visual cache
|
|
//GetXVisibleData will go to the back end
|
|
if(TI_IRowsetResynch==m_eTI||!g_fVisualCache)
|
|
{
|
|
if (g_fDeletedRow)
|
|
{
|
|
//resynch goes to the back end. it should see the deleted row if it is deleted
|
|
CHECK(GetLastVisibleData(hRow,m_hChgAccessor,pVisibleData,FALSE),DB_E_DELETEDROW);
|
|
}
|
|
else
|
|
{
|
|
//resynch - go get the row
|
|
CHECK(GetLastVisibleData(hRow,m_hChgAccessor,pVisibleData,FALSE),S_OK);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//if the row was deleted then refresh fails, no buffers are changed and GetLastVisibleData should work
|
|
//if the row was not deleted this should then also work
|
|
CHECK(GetLastVisibleData(hRow,m_hChgAccessor,pVisibleData,FALSE),S_OK);
|
|
}
|
|
|
|
//get original data (this is what the data first was, not what the back end is now)
|
|
CHECK(m_pChgIRowsetUpdate1->GetOriginalData(hRow,m_hChgAccessor,pOriginalData),S_OK);
|
|
|
|
//check the buffers
|
|
if (!g_fDeletedRow)
|
|
{
|
|
if(fOverWrite)
|
|
{
|
|
//resynch should compare with the visible data since resynch overwrote the pending buffer
|
|
COMPARE(CompareBuffer(pResynchData,pVisibleData,m_cBindings,m_rgBindings,m_pIMalloc,FALSE,FALSE,COMPARE_ONLY),TRUE);
|
|
//visible data and original should compare
|
|
COMPARE(CompareBuffer(pVisibleData,pOriginalData,m_cBindings,m_rgBindings,m_pIMalloc,FALSE,FALSE,COMPARE_ONLY),TRUE);
|
|
//pending and resynch should not be the same if the resynch did overwrite the pending buffer
|
|
COMPARE(CompareBuffer(pPendingData,pResynchData,m_cBindings,m_rgBindings,m_pIMalloc,FALSE,FALSE,COMPARE_ONLY),FALSE);
|
|
//first cache and original should NOT compare
|
|
COMPARE(CompareBuffer(pCacheData1,pOriginalData,m_cBindings,m_rgBindings,m_pIMalloc,FALSE,FALSE,COMPARE_ONLY),FALSE);
|
|
}
|
|
else
|
|
{
|
|
//resynch should not compare with the visible data since resynch did not overwrite the pending buffer
|
|
COMPARE(CompareBuffer(pResynchData,pVisibleData,m_cBindings,m_rgBindings,m_pIMalloc,FALSE,FALSE,COMPARE_ONLY),FALSE);
|
|
//first cache and original should compare
|
|
COMPARE(CompareBuffer(pCacheData1,pOriginalData,m_cBindings,m_rgBindings,m_pIMalloc,FALSE,FALSE,COMPARE_ONLY),TRUE);
|
|
//pending and resynch should be the same if the resynch did not overwrite the pending buffer
|
|
COMPARE(CompareBuffer(pPendingData,pResynchData,m_cBindings,m_rgBindings,m_pIMalloc,FALSE,FALSE,COMPARE_ONLY),TRUE);
|
|
}
|
|
}
|
|
//if refresh returned a deleted row then all calls after should be just like refresh was never called cause it failed.
|
|
else
|
|
{
|
|
if(TI_IRowsetResynch==m_eTI || !g_fVisualCache)
|
|
{
|
|
//if the row was deleted and the interface was Resynch or there was no visual cache
|
|
//then both Resych and GetVisibleData failed
|
|
//so there are no buffers to check
|
|
}
|
|
else
|
|
{
|
|
//it doesn't matter what fOverwrite is here because refresh failed
|
|
|
|
//visible data and original should compare if Refresh fails
|
|
COMPARE(CompareBuffer(pVisibleData,pOriginalData,m_cBindings,m_rgBindings,m_pIMalloc,FALSE,FALSE,COMPARE_ONLY),TRUE);
|
|
//pending and resynch should be the same if Refresh fails
|
|
COMPARE(CompareBuffer(pPendingData,pResynchData,m_cBindings,m_rgBindings,m_pIMalloc,FALSE,FALSE,COMPARE_ONLY),TRUE);
|
|
//first cache and original should compare if Refresh fails
|
|
COMPARE(CompareBuffer(pCacheData1,pOriginalData,m_cBindings,m_rgBindings,m_pIMalloc,FALSE,FALSE,COMPARE_ONLY),TRUE);
|
|
}
|
|
}
|
|
|
|
fResults=TRUE;
|
|
}
|
|
}
|
|
CLEANUP:
|
|
//clean up any left over pending changes
|
|
m_pChgIRowsetUpdate1->Undo(NULL,0,NULL,NULL,NULL,NULL);
|
|
m_pChgIRowsetUpdate2->Undo(NULL,0,NULL,NULL,NULL,NULL);
|
|
|
|
if (hRow != DB_NULL_HROW)
|
|
{
|
|
m_pChgIRowset->ReleaseRows(1, &hRow, NULL, NULL, NULL);
|
|
}
|
|
PROVIDER_FREE(pOriginalData);
|
|
PROVIDER_FREE(pResynchData);
|
|
PROVIDER_FREE(pPendingData);
|
|
PROVIDER_FREE(pVisibleData);
|
|
PROVIDER_FREE(pCacheData1);
|
|
PROVIDER_FREE(pOriginalData);
|
|
|
|
if (fResults)
|
|
{
|
|
return TEST_PASS;
|
|
}
|
|
else
|
|
{
|
|
return TEST_FAIL;
|
|
}
|
|
}
|
|
// }}
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(7)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc Pending insert
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCPropUpdateResynch::Variation_7()
|
|
{
|
|
HROW hRow = DB_NULL_HROW;
|
|
BOOL fResults = TEST_FAIL;
|
|
BOOL fOverWrite = TRUE;
|
|
|
|
if (m_eTI==TI_IRowsetRefreshFALSE)
|
|
{
|
|
fOverWrite=FALSE;
|
|
}
|
|
|
|
//(Pending) Insert a row ourselves and keep hRow
|
|
if (m_pChgRowset1->Insert(GetNextRowToInsert(), &hRow))
|
|
{
|
|
//Now do a ResynchRows
|
|
CHECK(ResynchRefresh(DB_NULL_HCHAPTER,1, &hRow, fOverWrite, &m_cRowsResynched, &m_rghRowsResynched, &m_rgRowStatus, FALSE), DB_E_ERRORSOCCURRED);
|
|
|
|
COMPARE(m_cRowsResynched,1);
|
|
COMPARE(m_rghRowsResynched[0],hRow);
|
|
COMPARE(DBROWSTATUS_E_PENDINGINSERT,m_rgRowStatus[0]);
|
|
fResults = TEST_PASS;
|
|
}
|
|
|
|
//clean up any left over pending changes
|
|
m_pChgIRowsetUpdate1->Undo(NULL,0,NULL,NULL,NULL,NULL);
|
|
m_pChgIRowsetUpdate2->Undo(NULL,0,NULL,NULL,NULL,NULL);
|
|
|
|
if (hRow != DB_NULL_HROW)
|
|
{
|
|
m_pChgIRowset->ReleaseRows(1, &hRow, NULL, NULL, NULL);
|
|
}
|
|
FreeOutParams();
|
|
if (fResults)
|
|
{
|
|
return TEST_PASS;
|
|
}
|
|
else
|
|
{
|
|
return TEST_FAIL;
|
|
}
|
|
}
|
|
// }}
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(8)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc Pending Delete
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCPropUpdateResynch::Variation_8()
|
|
{
|
|
HROW hRow = DB_NULL_HROW;
|
|
BOOL fResults = TEST_FAIL;
|
|
DBPENDINGSTATUS PendingRowStatus = (DBPENDINGSTATUS)JUNK_PTR;
|
|
DBPENDINGSTATUS *rgPendingRow = NULL;
|
|
DBPENDINGSTATUS PendingStatusReq = DBPENDINGSTATUS_NEW | DBPENDINGSTATUS_CHANGED | DBPENDINGSTATUS_DELETED;
|
|
DBCOUNTITEM uPRows = 0;
|
|
HROW *rghPRow = NULL;
|
|
BOOL fOverWrite = TRUE;
|
|
|
|
if (m_eTI==TI_IRowsetRefreshFALSE)
|
|
{
|
|
fOverWrite=FALSE;
|
|
}
|
|
|
|
//(Pending) Delete a row ourselves and keep hRow
|
|
if (m_pChgRowset1->Delete(GetNextRowToDelete(), &hRow))
|
|
{
|
|
//Now do a ResynchRows
|
|
CHECK(ResynchRefresh(DB_NULL_HCHAPTER,1, &hRow, fOverWrite, &m_cRowsResynched, &m_rghRowsResynched, &m_rgRowStatus, FALSE), S_OK);
|
|
|
|
//if overwrite is true then this is Resync or fOverwrite in Refresh is TRUE
|
|
//so there will be no pending status or pending rows
|
|
if (fOverWrite)
|
|
{
|
|
CHECK(m_pChgIRowsetUpdate1->GetRowStatus(NULL, 1, &hRow, &PendingRowStatus), S_OK);
|
|
|
|
//overwrite knocked off anything pending
|
|
COMPARE(DBPENDINGSTATUS_UNCHANGED,PendingRowStatus);
|
|
CHECK(m_pChgIRowsetUpdate1->GetPendingRows(NULL, PendingStatusReq, &uPRows, &rghPRow, &rgPendingRow), S_FALSE);
|
|
COMPARE(0,uPRows);
|
|
fResults = TEST_PASS;
|
|
}
|
|
//if fOverwrite is false there should be pending rows and pending row status
|
|
else
|
|
{
|
|
CHECK(m_pChgIRowsetUpdate1->GetRowStatus(NULL, 1, &hRow, &PendingRowStatus), S_OK);
|
|
|
|
//should still be pending
|
|
COMPARE(DBPENDINGSTATUS_DELETED,PendingRowStatus);
|
|
|
|
//leaves the pending row
|
|
CHECK(m_pChgIRowsetUpdate1->GetPendingRows(NULL, PendingStatusReq, &uPRows, &rghPRow, &rgPendingRow), S_OK);
|
|
COMPARE(DBPENDINGSTATUS_DELETED,rgPendingRow[0]);
|
|
COMPARE(1,uPRows);
|
|
//call update to xmit the deleted row
|
|
if (CHECK(m_pChgIRowsetUpdate1->Update(NULL, 1, &hRow, NULL, NULL, NULL), S_OK))
|
|
{
|
|
g_DeleteIncrement();
|
|
FreeOutParams();
|
|
//call resynch/refresh again to make sure the deleted row made it to the back end
|
|
//Now do a ResynchRows
|
|
CHECK(ResynchRefresh(DB_NULL_HCHAPTER,1, &hRow, fOverWrite, &m_cRowsResynched, &m_rghRowsResynched, &m_rgRowStatus, FALSE), DB_E_ERRORSOCCURRED);
|
|
|
|
COMPARE(m_cRowsResynched,1);
|
|
COMPARE(m_rghRowsResynched[0],hRow);
|
|
CompareOutParams(1, &hRow);
|
|
|
|
if (COMPARE(m_rgRowStatus[0], DBROWSTATUS_E_DELETED))
|
|
{
|
|
fResults = TEST_PASS;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
FreeOutParams();
|
|
//clean up any left over pending changes
|
|
m_pChgIRowsetUpdate1->Undo(NULL,0,NULL,NULL,NULL,NULL);
|
|
m_pChgIRowsetUpdate2->Undo(NULL,0,NULL,NULL,NULL,NULL);
|
|
|
|
if (hRow != DB_NULL_HROW)
|
|
{
|
|
m_pChgIRowset->ReleaseRows(1, &hRow, NULL, NULL, NULL);
|
|
}
|
|
PROVIDER_FREE(rghPRow);
|
|
PROVIDER_FREE(rgPendingRow);
|
|
if (fResults)
|
|
{
|
|
return TEST_PASS;
|
|
}
|
|
else
|
|
{
|
|
return TEST_FAIL;
|
|
}
|
|
}
|
|
// }}
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(9)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc insert, change and delete on a rowset
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCPropUpdateResynch::Variation_9()
|
|
{
|
|
IRowsetChange *pIRowsetChange = NULL;
|
|
BOOL fResults = TEST_SKIPPED;
|
|
BOOL fOverWrite = TRUE;
|
|
DBCOUNTITEM cRowsObtained = 0;
|
|
HROW *pHRows = NULL;
|
|
DBCOUNTITEM cRowsUpdated = 0;
|
|
DBCOUNTITEM cRowsUndone = 0;
|
|
HRESULT hr;
|
|
|
|
BYTE *pRowsetDataFirst = NULL;
|
|
BYTE *pRowsetDataLast = NULL;
|
|
BYTE *pRowsetDataNew = NULL;
|
|
|
|
BYTE *pVisibleDataFirst = NULL;
|
|
BYTE *pVisibleDataLast = NULL;
|
|
BYTE *pVisibleDataNew = NULL;
|
|
|
|
BYTE *pResynchedRowsetDataFirst = NULL;
|
|
BYTE *pResynchedRowsetDataLast = NULL;
|
|
BYTE *pResynchedRowsetDataNew = NULL;
|
|
|
|
BYTE *pResynchedVisibleDataFirst = NULL;
|
|
BYTE *pResynchedVisibleDataLast = NULL;
|
|
BYTE *pResynchedVisibleDataNew = NULL;
|
|
|
|
BYTE *pChangeData = NULL;
|
|
BYTE *pInsertData = NULL;
|
|
|
|
HROW HRowOut;
|
|
HROW *pHRowOut = &HRowOut;
|
|
HROW *pHRowUpdated = NULL;
|
|
|
|
|
|
if (m_eTI==TI_IRowsetRefreshFALSE)
|
|
{
|
|
fOverWrite=FALSE;
|
|
}
|
|
|
|
//Not all drivers allow starting a txn with rowsets
|
|
//open, so release them before starting a txn
|
|
ReleaseResynchObjects();
|
|
|
|
//start a txn
|
|
hr=m_pChgRowset1->m_pITxnLocal->StartTransaction(ISOLATIONLEVEL_CHAOS, 0, NULL, NULL);
|
|
|
|
if (E_FAIL==hr)
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
if (S_OK!=hr)
|
|
{
|
|
fResults=TEST_FAIL;
|
|
goto CLEANUP;
|
|
}
|
|
|
|
//alloc memory for the row buffers
|
|
pRowsetDataFirst = (BYTE *)PROVIDER_ALLOC(m_cbRowSize);
|
|
pRowsetDataLast = (BYTE *)PROVIDER_ALLOC(m_cbRowSize);
|
|
pRowsetDataNew = (BYTE *)PROVIDER_ALLOC(m_cbRowSize);
|
|
|
|
pVisibleDataFirst = (BYTE *)PROVIDER_ALLOC(m_cbRowSize);
|
|
pVisibleDataLast = (BYTE *)PROVIDER_ALLOC(m_cbRowSize);
|
|
pVisibleDataNew = (BYTE *)PROVIDER_ALLOC(m_cbRowSize);
|
|
|
|
pResynchedVisibleDataFirst = (BYTE *)PROVIDER_ALLOC(m_cbRowSize);
|
|
pResynchedVisibleDataLast = (BYTE *)PROVIDER_ALLOC(m_cbRowSize);
|
|
pResynchedVisibleDataNew = (BYTE *)PROVIDER_ALLOC(m_cbRowSize);
|
|
|
|
pResynchedRowsetDataFirst = (BYTE *)PROVIDER_ALLOC(m_cbRowSize);
|
|
pResynchedRowsetDataLast = (BYTE *)PROVIDER_ALLOC(m_cbRowSize);
|
|
pResynchedRowsetDataNew = (BYTE *)PROVIDER_ALLOC(m_cbRowSize);
|
|
|
|
pChangeData = (BYTE *)PROVIDER_ALLOC(m_cbRowSize);
|
|
pInsertData = (BYTE *)PROVIDER_ALLOC(m_cbRowSize);
|
|
|
|
if (!pRowsetDataFirst || !pRowsetDataLast || !pRowsetDataNew)
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
if (!pVisibleDataFirst || !pVisibleDataLast || !pVisibleDataNew)
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
if (!pResynchedVisibleDataFirst || !pResynchedVisibleDataLast || !pResynchedVisibleDataNew)
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
if (!pResynchedRowsetDataFirst || !pResynchedRowsetDataLast || !pResynchedRowsetDataNew)
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
if (!pChangeData || !pInsertData)
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
|
|
memset(pRowsetDataFirst,0,(size_t)m_cbRowSize);
|
|
memset(pRowsetDataLast,0,(size_t)m_cbRowSize);
|
|
memset(pRowsetDataNew,0,(size_t)m_cbRowSize);
|
|
|
|
memset(pVisibleDataFirst,0,(size_t)m_cbRowSize);
|
|
memset(pVisibleDataLast,0,(size_t)m_cbRowSize);
|
|
memset(pVisibleDataNew,0,(size_t)m_cbRowSize);
|
|
|
|
memset(pResynchedVisibleDataFirst,0,(size_t)m_cbRowSize);
|
|
memset(pResynchedVisibleDataLast,0,(size_t)m_cbRowSize);
|
|
memset(pResynchedVisibleDataNew,0,(size_t)m_cbRowSize);
|
|
|
|
memset(pResynchedRowsetDataFirst,0,(size_t)m_cbRowSize);
|
|
memset(pResynchedRowsetDataLast,0,(size_t)m_cbRowSize);
|
|
memset(pResynchedRowsetDataNew,0,(size_t)m_cbRowSize);
|
|
|
|
memset(pChangeData,0,(size_t)m_cbRowSize);
|
|
memset(pInsertData,0,(size_t)m_cbRowSize);
|
|
|
|
|
|
//Set data for all columns
|
|
CHECK(FillInputBindings( m_pChgRowset1->m_pTable,
|
|
DBACCESSOR_ROWDATA,
|
|
m_cBindings,
|
|
m_rgBindings,
|
|
&pChangeData,
|
|
g_ulLastActualInsert+1,
|
|
m_pChgRowset1->m_pTable->CountColumnsOnTable(),
|
|
m_pChgRowset1->m_rgTableColOrds), S_OK);
|
|
|
|
//Set data for all columns
|
|
CHECK(FillInputBindings( m_pChgRowset1->m_pTable,
|
|
DBACCESSOR_ROWDATA,
|
|
m_cBindings,
|
|
m_rgBindings,
|
|
&pInsertData,
|
|
g_ulLastActualInsert+2,
|
|
m_pChgRowset1->m_pTable->CountColumnsOnTable(),
|
|
m_pChgRowset1->m_rgTableColOrds), S_OK);
|
|
|
|
//If change isn't supported this variation isn't applicable
|
|
if (!VerifyInterface(m_pChgRowset1->m_pIAccessor, IID_IRowsetChange,ROWSET_INTERFACE, (IUnknown **)&pIRowsetChange))
|
|
{
|
|
return fResults;
|
|
}
|
|
|
|
fResults = TEST_FAIL;
|
|
|
|
//Get all the rows, ask for more than enough
|
|
if (CHECK(m_pChgIRowset->GetNextRows(NULL, 0, NUM_ROWS * 3, &cRowsObtained, &pHRows), DB_S_ENDOFROWSET))
|
|
{
|
|
//get first and last row buffers
|
|
CHECK(m_pChgIRowset->GetData(pHRows[0], m_hChgAccessor, pRowsetDataFirst), S_OK);
|
|
CHECK(m_pChgIRowset->GetData(pHRows[cRowsObtained-1], m_hChgAccessor, pRowsetDataLast), S_OK);
|
|
|
|
//change the first row
|
|
CHECK(pIRowsetChange->SetData(pHRows[0], m_hChgAccessor, pChangeData), S_OK);
|
|
|
|
//delete the last row
|
|
CHECK(pIRowsetChange->DeleteRows(NULL, 1, &pHRows[cRowsObtained-1], NULL), S_OK);
|
|
|
|
//insert a row
|
|
CHECK(pIRowsetChange->InsertRow(NULL, m_hChgAccessor, pInsertData, &HRowOut), S_OK);
|
|
|
|
//getLastVisibleData the row buffers
|
|
CHECK(GetLastVisibleData(pHRows[0], m_hChgAccessor, pVisibleDataFirst,FALSE),S_OK);
|
|
CHECK(GetLastVisibleData(pHRows[cRowsObtained-1], m_hChgAccessor, pVisibleDataLast,FALSE),S_OK);
|
|
CHECK(GetLastVisibleData(pHRowOut[0], m_hChgAccessor, pVisibleDataNew,FALSE),DB_E_PENDINGINSERT);
|
|
|
|
//Resynch all the rows except the newly pending inserted row
|
|
CHECK(ResynchRefresh(DB_NULL_HCHAPTER,cRowsObtained, pHRows, fOverWrite, NULL, NULL, NULL, FALSE), S_OK);
|
|
|
|
//getLastVisibleData the row buffers again
|
|
CHECK(GetLastVisibleData(pHRows[0], m_hChgAccessor, pResynchedVisibleDataFirst,FALSE),S_OK);
|
|
CHECK(GetLastVisibleData(pHRows[cRowsObtained-1], m_hChgAccessor, pResynchedVisibleDataLast,FALSE),S_OK);
|
|
CHECK(GetLastVisibleData(pHRowOut[0], m_hChgAccessor, pResynchedVisibleDataNew,FALSE),DB_E_PENDINGINSERT);
|
|
|
|
//get resyched data
|
|
CHECK(m_pChgIRowset->GetData(pHRows[0], m_hChgAccessor, pResynchedRowsetDataFirst), S_OK);
|
|
CHECK(m_pChgIRowset->GetData(pHRows[cRowsObtained-1], m_hChgAccessor, pResynchedRowsetDataLast), S_OK);
|
|
hr = m_pChgIRowset->GetData(pHRowOut[0], m_hChgAccessor, pResynchedRowsetDataNew);
|
|
if (S_OK!=hr && DB_S_ERRORSOCCURRED!=hr)
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
|
|
if (fOverWrite)
|
|
{
|
|
//undo the insert since it is still pending
|
|
CHECK(m_pChgIRowsetUpdate1->Undo(NULL,1,pHRowOut,NULL,NULL,NULL),S_OK);
|
|
//call update and make sure no work gets done cause changes were resynched away
|
|
CHECK(m_pChgIRowsetUpdate1->Update(NULL, 0, NULL, &cRowsUpdated, &pHRowUpdated, NULL), S_OK);
|
|
m_pChgIRowset->ReleaseRows(cRowsUpdated, pHRowUpdated, NULL, NULL, NULL);
|
|
PROVIDER_FREE(pHRowUpdated);
|
|
if (cRowsUpdated)
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//lose these changes which are still here because pending changes should not be overwritten
|
|
CHECK(m_pChgIRowsetUpdate1->Undo(NULL,0,NULL,&cRowsUndone,&pHRowUpdated,NULL),S_OK);
|
|
m_pChgIRowset->ReleaseRows(cRowsUpdated, pHRowUpdated, NULL, NULL, NULL);
|
|
PROVIDER_FREE(pHRowUpdated);
|
|
if (cRowsUndone!=3)
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
}
|
|
|
|
//compare buffers
|
|
COMPARE(CompareBuffer(pRowsetDataFirst,pVisibleDataFirst,m_cBindings,m_rgBindings,m_pIMalloc,FALSE,FALSE,COMPARE_ONLY),TRUE);
|
|
COMPARE(CompareBuffer(pRowsetDataLast,pVisibleDataLast,m_cBindings,m_rgBindings,m_pIMalloc,FALSE,FALSE,COMPARE_ONLY),TRUE);
|
|
|
|
COMPARE(CompareBuffer(pResynchedVisibleDataFirst,pVisibleDataFirst,m_cBindings,m_rgBindings,m_pIMalloc,FALSE,FALSE,COMPARE_ONLY),TRUE);
|
|
COMPARE(CompareBuffer(pResynchedVisibleDataLast,pVisibleDataLast,m_cBindings,m_rgBindings,m_pIMalloc,FALSE,FALSE,COMPARE_ONLY),TRUE);
|
|
|
|
//if the pending row are not refreshed
|
|
//they will have the changed values
|
|
//otherwise they will have the old values
|
|
if (!fOverWrite)
|
|
{
|
|
COMPARE(CompareBuffer(pResynchedRowsetDataFirst,pChangeData,m_cBindings,m_rgBindings,m_pIMalloc,TRUE,FALSE,COMPARE_ONLY),TRUE);
|
|
//hard to compare a buffer from GetData the was a pending insert cause it can easily return rows as unavailable
|
|
//COMPARE(CompareBuffer(pResynchedRowsetDataNew,pInsertData,m_cBindings,m_rgBindings,m_pIMalloc,FALSE,FALSE,COMPARE_ONLY),TRUE);
|
|
}
|
|
else
|
|
{
|
|
COMPARE(CompareBuffer(pResynchedRowsetDataFirst,pVisibleDataFirst,m_cBindings,m_rgBindings,m_pIMalloc,FALSE,FALSE,COMPARE_ONLY),TRUE);
|
|
COMPARE(CompareBuffer(pResynchedRowsetDataLast,pVisibleDataLast,m_cBindings,m_rgBindings,m_pIMalloc,FALSE,FALSE,COMPARE_ONLY),TRUE);
|
|
}
|
|
|
|
//do the changes again. they should work cause they were killed in the resynch above unless they were pending
|
|
//in which case they were undone
|
|
m_pChgIRowset->ReleaseRows(1, pHRowOut, NULL, NULL, NULL);
|
|
|
|
//change the first row
|
|
CHECK(pIRowsetChange->SetData(pHRows[0], m_hChgAccessor, pChangeData), S_OK);
|
|
|
|
//delete the last row
|
|
CHECK(pIRowsetChange->DeleteRows(NULL, 1, &pHRows[cRowsObtained-1], NULL), S_OK);
|
|
|
|
//insert a row
|
|
CHECK(pIRowsetChange->InsertRow(NULL, m_hChgAccessor, pInsertData, &HRowOut), S_OK);
|
|
|
|
//update - xmit these changes to the back end
|
|
CHECK(m_pChgIRowsetUpdate1->Update(NULL, 0, NULL, &cRowsUpdated, &pHRowUpdated, NULL), S_OK);
|
|
m_pChgIRowset->ReleaseRows(cRowsUpdated, pHRowUpdated, NULL, NULL, NULL);
|
|
PROVIDER_FREE(pHRowUpdated);
|
|
if (cRowsUpdated!=3)
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
|
|
//getLastVisibleData the row buffers
|
|
CHECK(GetLastVisibleData(pHRows[0], m_hChgAccessor, pVisibleDataFirst,FALSE),S_OK);
|
|
//always have to see own deletes no matter if there is a visual cache
|
|
CHECK(GetLastVisibleData(pHRows[cRowsObtained-1], m_hChgAccessor, pVisibleDataLast,FALSE),DB_E_DELETEDROW);
|
|
|
|
//can we see newly inserted rows
|
|
if (m_fStrongIdentity)
|
|
{
|
|
CHECK(GetLastVisibleData(pHRowOut[0], m_hChgAccessor, pVisibleDataNew,FALSE),S_OK);
|
|
}
|
|
else
|
|
{
|
|
CHECK(GetLastVisibleData(pHRowOut[0], m_hChgAccessor, pVisibleDataNew,FALSE),DB_E_NEWLYINSERTED);
|
|
}
|
|
|
|
//Resynch all the rows except the newly pending inserted row
|
|
//should error here on the deleted row
|
|
CHECK(ResynchRefresh(DB_NULL_HCHAPTER,cRowsObtained, pHRows, fOverWrite, NULL, NULL, NULL, FALSE), DB_S_ERRORSOCCURRED);
|
|
|
|
//getLastVisibleData the row buffers again
|
|
CHECK(GetLastVisibleData(pHRows[0], m_hChgAccessor, pResynchedVisibleDataFirst,FALSE),S_OK);
|
|
//always have to see own deletes no matter if there is a visual cache
|
|
CHECK(GetLastVisibleData(pHRows[cRowsObtained-1], m_hChgAccessor, pVisibleDataLast,FALSE),DB_E_DELETEDROW);
|
|
|
|
//can we see newly inserted rows
|
|
if (m_fStrongIdentity)
|
|
{
|
|
CHECK(GetLastVisibleData(pHRowOut[0], m_hChgAccessor, pResynchedVisibleDataNew,FALSE),S_OK);
|
|
}
|
|
else
|
|
{
|
|
CHECK(GetLastVisibleData(pHRowOut[0], m_hChgAccessor, pResynchedVisibleDataNew,FALSE),DB_E_NEWLYINSERTED);
|
|
}
|
|
|
|
//get resyched data
|
|
CHECK(m_pChgIRowset->GetData(pHRows[0], m_hChgAccessor, pResynchedRowsetDataFirst), S_OK);
|
|
|
|
//compare buffers
|
|
COMPARE(CompareBuffer(pVisibleDataFirst,pChangeData,m_cBindings,m_rgBindings,m_pIMalloc,TRUE,FALSE,COMPARE_ONLY),TRUE);
|
|
COMPARE(CompareBuffer(pResynchedVisibleDataFirst,pVisibleDataFirst,m_cBindings,m_rgBindings,m_pIMalloc,FALSE,FALSE,COMPARE_ONLY),TRUE);
|
|
|
|
//no pending changes, fOverWrite won't matter here
|
|
COMPARE(CompareBuffer(pResynchedRowsetDataFirst,pVisibleDataFirst,m_cBindings,m_rgBindings,m_pIMalloc,FALSE,FALSE,COMPARE_ONLY),TRUE);
|
|
|
|
if (m_fStrongIdentity)
|
|
{
|
|
COMPARE(CompareBuffer(pVisibleDataNew, pInsertData,m_cBindings,m_rgBindings,m_pIMalloc,TRUE,FALSE,COMPARE_ONLY),TRUE);
|
|
COMPARE(CompareBuffer(pResynchedVisibleDataNew,pInsertData,m_cBindings,m_rgBindings,m_pIMalloc,TRUE,FALSE,COMPARE_ONLY),TRUE);
|
|
}
|
|
|
|
fResults = TEST_PASS;
|
|
}
|
|
CLEANUP:
|
|
//clean up any changes this variation made on the back end
|
|
if(m_pChgRowset1)
|
|
{
|
|
m_pChgRowset1->m_pITxnLocal->Abort(NULL,FALSE,FALSE);
|
|
}
|
|
if (m_pChgIRowset)
|
|
{
|
|
//release all the rows
|
|
m_pChgIRowset->ReleaseRows(cRowsObtained, pHRows, NULL, NULL, NULL);
|
|
PROVIDER_FREE(pHRows);
|
|
m_pChgIRowset->ReleaseRows(1, pHRowOut, NULL, NULL, NULL);
|
|
}
|
|
|
|
//free the row buffers
|
|
PROVIDER_FREE(pChangeData);
|
|
PROVIDER_FREE(pInsertData);
|
|
|
|
PROVIDER_FREE(pRowsetDataFirst);
|
|
PROVIDER_FREE(pRowsetDataLast);
|
|
PROVIDER_FREE(pRowsetDataNew);
|
|
|
|
PROVIDER_FREE(pVisibleDataFirst);
|
|
PROVIDER_FREE(pVisibleDataLast);
|
|
PROVIDER_FREE(pVisibleDataNew);
|
|
|
|
PROVIDER_FREE(pResynchedVisibleDataFirst);
|
|
PROVIDER_FREE(pResynchedVisibleDataLast);
|
|
PROVIDER_FREE(pResynchedVisibleDataNew);
|
|
|
|
PROVIDER_FREE(pResynchedRowsetDataFirst);
|
|
PROVIDER_FREE(pResynchedRowsetDataLast);
|
|
PROVIDER_FREE(pResynchedRowsetDataNew);
|
|
|
|
SAFE_RELEASE(pIRowsetChange);
|
|
|
|
return fResults;
|
|
}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_TERMINATE_METHOD
|
|
//--------------------------------------------------------------------
|
|
// @mfunc TestCase Termination Routine
|
|
//
|
|
// @rdesc TRUE or FALSE
|
|
//
|
|
BOOL TCPropUpdateResynch::Terminate()
|
|
{
|
|
if (m_pChgIRowsetUpdate1)
|
|
{
|
|
m_pChgIRowsetUpdate1->Release();
|
|
m_pChgIRowsetUpdate1 = NULL;
|
|
}
|
|
|
|
if (m_pChgIRowsetUpdate2)
|
|
{
|
|
m_pChgIRowsetUpdate2->Release();
|
|
m_pChgIRowsetUpdate2 = NULL;
|
|
}
|
|
|
|
// {{ TCW_TERM_BASECLASS_CHECK2
|
|
return(CResynchRefresh::Terminate());
|
|
} // }}
|
|
// }}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_TC_PROTOTYPE(TCZombieResynch)
|
|
//*-----------------------------------------------------------------------
|
|
//| Test Case: TCZombieResynch - Rowset Preservation tests
|
|
//| Created: 06/02/96
|
|
//*-----------------------------------------------------------------------
|
|
|
|
//--------------------------------------------------------------------
|
|
// @mfunc Tests zombie state (or lack thereof)
|
|
//
|
|
// @rdesc TRUE or FALSE
|
|
//
|
|
int TCZombieResynch::TestZombie(ETXN eTxn, BOOL fRetaining)
|
|
{
|
|
IRowset *pIRowset = NULL;
|
|
BOOL fResults;
|
|
HROW *phRow = &m_hRow;
|
|
ULONG i = 0;
|
|
DBCOUNTITEM cRowsObtained = 0;
|
|
IRowsetResynch *pIRowsetResynch = NULL;
|
|
IRowsetRefresh *pIRowsetRefresh = NULL;
|
|
HROW *rgTestHRow = (HROW *)JUNK_PTR;
|
|
DBROWSTATUS *rgTestStatus = (DBROWSTATUS *)JUNK_PTR;
|
|
DBCOUNTITEM cRowsResynched = 0;
|
|
|
|
if (m_eTI==TI_IRowsetResynch)
|
|
{
|
|
//Start a transaction. Create a rowset with IRowsetResynch pointer.
|
|
if(!StartTransaction(USE_SUPPORTED_SELECT_ALLFROMTBL, (IUnknown **)&pIRowsetResynch,1, &m_PropSet))
|
|
goto CLEANUP;
|
|
}
|
|
else
|
|
{
|
|
//Start a transaction. Create a rowset with IRowsetRefresh pointer.
|
|
if(!StartTransaction(USE_SUPPORTED_SELECT_ALLFROMTBL, (IUnknown **)&pIRowsetRefresh,1, &m_PropSet))
|
|
goto CLEANUP;
|
|
}
|
|
|
|
//Get an accessor
|
|
if (!CHECK(GetAccessorAndBindings(m_pIRowset, DBACCESSOR_ROWDATA,
|
|
&m_hAccessor, &m_rgBindings, &m_cBindings, &m_cbRowSize), S_OK))
|
|
goto CLEANUP;
|
|
|
|
//Get a big enough data buffer
|
|
m_pData = (BYTE *)PROVIDER_ALLOC(m_cbRowSize);
|
|
if (!m_pData)
|
|
goto CLEANUP;
|
|
memset(m_pData,0,(size_t)m_cbRowSize);
|
|
|
|
//Get an hRow
|
|
if (!CHECK(m_pIRowset->GetNextRows(NULL, 0, 1, &cRowsObtained, &phRow), S_OK))
|
|
goto CLEANUP;
|
|
|
|
//Test Commit
|
|
if (eTxn == ECOMMIT)
|
|
{
|
|
if(!GetCommit(fRetaining))
|
|
goto CLEANUP;
|
|
|
|
if(!m_fCommitPreserve)
|
|
{
|
|
if (m_eTI==TI_IRowsetResynch)
|
|
{
|
|
//test zombie
|
|
TESTC_(pIRowsetResynch->GetVisibleData(m_hRow, m_hAccessor, m_pData),E_UNEXPECTED);
|
|
|
|
TESTC_(pIRowsetResynch->ResynchRows(1, &m_hRow, &cRowsResynched, &rgTestHRow, &rgTestStatus), E_UNEXPECTED);
|
|
}
|
|
else
|
|
{
|
|
if(m_eTI==TI_IRowsetRefreshTRUE)
|
|
{
|
|
TESTC_(pIRowsetRefresh->RefreshVisibleData(DB_NULL_HCHAPTER,1, &m_hRow, TRUE, &cRowsResynched, &rgTestHRow, &rgTestStatus), E_UNEXPECTED);
|
|
}
|
|
else
|
|
{
|
|
TESTC_(pIRowsetRefresh->RefreshVisibleData(DB_NULL_HCHAPTER,1, &m_hRow, FALSE, &cRowsResynched, &rgTestHRow, &rgTestStatus), E_UNEXPECTED);
|
|
}
|
|
//test zombie
|
|
TESTC_(pIRowsetRefresh->GetLastVisibleData(m_hRow, m_hAccessor, m_pData),E_UNEXPECTED);
|
|
}
|
|
|
|
//Make sure all out parameters are zeroed/nulled out on error
|
|
COMPARE(cRowsResynched, 0);
|
|
COMPARE(rgTestHRow, NULL);
|
|
COMPARE(rgTestStatus, NULL);
|
|
fResults=TRUE;
|
|
}
|
|
else
|
|
{
|
|
if (m_eTI==TI_IRowsetResynch)
|
|
{
|
|
//test the rowset should be fully functional
|
|
TESTC_(pIRowsetResynch->GetVisibleData(m_hRow, m_hAccessor, m_pData),S_OK);
|
|
|
|
TESTC_(pIRowsetResynch->ResynchRows(1, &m_hRow, NULL, NULL, NULL), S_OK);
|
|
|
|
fResults=TRUE;
|
|
}
|
|
else
|
|
{
|
|
if (m_eTI==TI_IRowsetRefreshTRUE)
|
|
{
|
|
TESTC_(pIRowsetRefresh->RefreshVisibleData(DB_NULL_HCHAPTER,1, &m_hRow, TRUE, NULL, NULL, NULL), S_OK);
|
|
}
|
|
else
|
|
{
|
|
TESTC_(pIRowsetRefresh->RefreshVisibleData(DB_NULL_HCHAPTER,1, &m_hRow, FALSE, NULL, NULL, NULL), S_OK);
|
|
}
|
|
//test the rowset should be fully functional
|
|
TESTC_(pIRowsetRefresh->GetLastVisibleData(m_hRow, m_hAccessor, m_pData),S_OK);
|
|
fResults=TRUE;
|
|
}
|
|
}
|
|
}
|
|
//Test Abort
|
|
else
|
|
{
|
|
if(!GetAbort(fRetaining))
|
|
goto CLEANUP;
|
|
|
|
if(!m_fAbortPreserve)
|
|
{
|
|
if (m_eTI==TI_IRowsetResynch)
|
|
{
|
|
//test zombie
|
|
TESTC_(pIRowsetResynch->GetVisibleData(m_hRow, m_hAccessor, m_pData),E_UNEXPECTED);
|
|
|
|
TESTC_(pIRowsetResynch->ResynchRows(1, &m_hRow, NULL,&rgTestHRow, &rgTestStatus), E_UNEXPECTED);
|
|
}
|
|
else
|
|
{
|
|
if (m_eTI==TI_IRowsetRefreshTRUE)
|
|
{
|
|
TESTC_(pIRowsetRefresh->RefreshVisibleData(DB_NULL_HCHAPTER,1, &m_hRow, TRUE, NULL,&rgTestHRow, &rgTestStatus), E_UNEXPECTED);
|
|
}
|
|
else
|
|
{
|
|
TESTC_(pIRowsetRefresh->RefreshVisibleData(DB_NULL_HCHAPTER,1, &m_hRow, FALSE, NULL,&rgTestHRow, &rgTestStatus), E_UNEXPECTED);
|
|
}
|
|
//test zombie
|
|
TESTC_(pIRowsetRefresh->GetLastVisibleData(m_hRow, m_hAccessor, m_pData),E_UNEXPECTED);
|
|
}
|
|
|
|
//Add the bonus test of checking that rgTestHRow and
|
|
//rgTestStatus are untouched since pcRowsResynched is NULL
|
|
//on the call above to ResynchRows
|
|
COMPARE(rgTestHRow, (HROW *)JUNK_PTR);
|
|
COMPARE(rgTestStatus, (DBROWSTATUS *)JUNK_PTR);
|
|
|
|
fResults=TRUE;
|
|
}
|
|
else
|
|
{
|
|
if (m_eTI==TI_IRowsetResynch)
|
|
{
|
|
//test the rowset should be fully functional
|
|
TESTC_(pIRowsetResynch->GetVisibleData(m_hRow, m_hAccessor, m_pData),S_OK);
|
|
TESTC_(pIRowsetResynch->ResynchRows(1, &m_hRow, NULL,NULL, NULL), S_OK);
|
|
|
|
fResults=TRUE;
|
|
}
|
|
else
|
|
{
|
|
if (m_eTI==TI_IRowsetRefreshTRUE)
|
|
{
|
|
TESTC_(pIRowsetRefresh->RefreshVisibleData(DB_NULL_HCHAPTER,1, &m_hRow, TRUE, NULL,NULL, NULL), S_OK);
|
|
}
|
|
else
|
|
{
|
|
TESTC_(pIRowsetRefresh->RefreshVisibleData(DB_NULL_HCHAPTER,1, &m_hRow, FALSE, NULL,NULL, NULL), S_OK);
|
|
}
|
|
//test the rowset should be fully functional
|
|
TESTC_(pIRowsetRefresh->GetLastVisibleData(m_hRow, m_hAccessor, m_pData),S_OK);
|
|
|
|
fResults=TRUE;
|
|
}
|
|
}
|
|
}
|
|
CLEANUP:
|
|
//release the accessor
|
|
if (m_hAccessor != DB_NULL_HACCESSOR)
|
|
{
|
|
CHECK(m_pIAccessor->ReleaseAccessor(m_hAccessor, NULL),S_OK);
|
|
m_hAccessor = DB_NULL_HACCESSOR;
|
|
}
|
|
|
|
//and the memory
|
|
if (m_rgBindings)
|
|
{
|
|
PROVIDER_FREE(m_rgBindings);
|
|
m_rgBindings = NULL;
|
|
}
|
|
if (m_pData)
|
|
{
|
|
PROVIDER_FREE(m_pData);
|
|
m_pData = NULL;
|
|
}
|
|
|
|
//release the row handle
|
|
if(m_hRow != DB_NULL_HROW)
|
|
CHECK(m_pIRowset->ReleaseRows(1, &m_hRow, NULL, NULL, NULL),S_OK);
|
|
|
|
if(pIRowsetResynch)
|
|
{
|
|
pIRowsetResynch->Release();
|
|
pIRowsetResynch=NULL;
|
|
}
|
|
if(pIRowsetRefresh)
|
|
{
|
|
pIRowsetRefresh->Release();
|
|
pIRowsetRefresh=NULL;
|
|
}
|
|
//clean up. Expected S_OK.
|
|
if (fRetaining)
|
|
CleanUpTransaction(S_OK);
|
|
else
|
|
CleanUpTransaction(XACT_E_NOTRANSACTION);
|
|
|
|
if(fResults)
|
|
return TEST_PASS;
|
|
else
|
|
return TEST_FAIL;
|
|
}
|
|
|
|
//--------------------------------------------------------------------
|
|
// @mfunc TestCase Initialization Routine
|
|
//
|
|
// @rdesc TRUE or FALSE
|
|
//
|
|
BOOL TCZombieResynch::Init()
|
|
{
|
|
if (TEST_SKIPPED==fnInterfaceSupported())
|
|
{
|
|
return TEST_SKIPPED;
|
|
}
|
|
|
|
// {{ TCW_INIT_BASECLASS_CHECK
|
|
if(CTransaction::Init())
|
|
// }}
|
|
{
|
|
if (m_eTI==TI_IRowsetResynch)
|
|
{
|
|
//Build our property set for rowset properties
|
|
m_DBProp.dwPropertyID = DBPROP_IRowsetResynch;
|
|
m_DBProp.dwOptions = 0;
|
|
m_DBProp.colid = DB_NULLID;
|
|
m_DBProp.vValue.vt = VT_BOOL;
|
|
V_BOOL(&(m_DBProp.vValue)) = VARIANT_TRUE;
|
|
|
|
m_PropSet.rgProperties = &m_DBProp;
|
|
m_PropSet.cProperties = 1;
|
|
m_PropSet.guidPropertySet = DBPROPSET_ROWSET;
|
|
|
|
//Init data members
|
|
m_hAccessor = DB_NULL_HACCESSOR;
|
|
m_hRow = DB_NULL_HROW;
|
|
m_cBindings = 0;
|
|
m_rgBindings = NULL;
|
|
m_cbRowSize = 0;
|
|
m_pData = NULL;
|
|
|
|
//register interface to be tested
|
|
if(RegisterInterface(ROWSET_INTERFACE, IID_IRowsetResynch, 1, &m_PropSet))
|
|
return TRUE;
|
|
}
|
|
else
|
|
{
|
|
//Build our property set for rowset properties
|
|
m_DBProp.dwPropertyID = DBPROP_IRowsetRefresh;
|
|
m_DBProp.dwOptions = 0;
|
|
m_DBProp.colid = DB_NULLID;
|
|
m_DBProp.vValue.vt = VT_BOOL;
|
|
V_BOOL(&(m_DBProp.vValue)) = VARIANT_TRUE;
|
|
|
|
m_PropSet.rgProperties = &m_DBProp;
|
|
m_PropSet.cProperties = 1;
|
|
m_PropSet.guidPropertySet = DBPROPSET_ROWSET;
|
|
|
|
//Init data members
|
|
m_hAccessor = DB_NULL_HACCESSOR;
|
|
m_hRow = DB_NULL_HROW;
|
|
m_cBindings = 0;
|
|
m_rgBindings = NULL;
|
|
m_cbRowSize = 0;
|
|
m_pData = NULL;
|
|
|
|
//register interface to be tested
|
|
if(RegisterInterface(ROWSET_INTERFACE, IID_IRowsetRefresh, 1, &m_PropSet))
|
|
return TRUE;
|
|
}
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(1)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc Commit with fRetaining = TRUE
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCZombieResynch::Variation_1()
|
|
{
|
|
return TestZombie(ECOMMIT, TRUE);
|
|
}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(2)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc Commit with fRetaining = FALSE
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCZombieResynch::Variation_2()
|
|
{
|
|
return TestZombie(ECOMMIT, FALSE);
|
|
}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(3)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc Abort with fRetaining = TRUE
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCZombieResynch::Variation_3()
|
|
{
|
|
return TestZombie(EABORT, TRUE);
|
|
}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(4)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc Abort with fRetaining = FALSE
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCZombieResynch::Variation_4()
|
|
{
|
|
return TestZombie(EABORT, FALSE);
|
|
}
|
|
// }}
|
|
|
|
// {{ TCW_TERMINATE_METHOD
|
|
//--------------------------------------------------------------------
|
|
// @mfunc TestCase Termination Routine
|
|
//
|
|
// @rdesc TRUE or FALSE
|
|
//
|
|
BOOL TCZombieResynch::Terminate()
|
|
{
|
|
// {{ TCW_TERM_BASECLASS_CHECK2
|
|
return(CTransaction::Terminate());
|
|
} // }}
|
|
// }}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_TC_PROTOTYPE(TCExtendedErrorsResynch)
|
|
//*-----------------------------------------------------------------------
|
|
//| Test Case: TCExtendedErrorsResynch - Extended Errors
|
|
//| Created: 07/30/96
|
|
//*-----------------------------------------------------------------------
|
|
|
|
//--------------------------------------------------------------------
|
|
// @mfunc TestCase Initialization Routine
|
|
//
|
|
// @rdesc TRUE or FALSE
|
|
//
|
|
BOOL TCExtendedErrorsResynch::Init()
|
|
{
|
|
//Create an object for checking extended errors, which will use
|
|
//m_pError to increment the error count as needed.
|
|
//m_pExtError = new CExtError(m_pThisTestModule->m_ProviderClsid, m_pError);
|
|
|
|
//if (!m_pExtError)
|
|
// return FALSE;
|
|
|
|
if (TEST_SKIPPED==fnInterfaceSupported())
|
|
{
|
|
return TEST_SKIPPED;
|
|
}
|
|
|
|
// {{ TCW_INIT_BASECLASS_CHECK
|
|
if(CResynchRefresh::Init(m_eTI))
|
|
// }}
|
|
{
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(1)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc Valid IRowsetResynch calls with previous error object existing.
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCExtendedErrorsResynch::Variation_1()
|
|
{
|
|
DBCOUNTITEM cRowsObtained = 0;
|
|
HROW hRow = DB_NULL_HROW;
|
|
HROW *phRow = &hRow;
|
|
BOOL fResults = FALSE;
|
|
DBPROPID PropCanHoldRows = DBPROP_CANHOLDROWS;
|
|
HRESULT hr = S_OK;
|
|
BOOL fOverWrite = TRUE;
|
|
|
|
if (m_eTI==TI_IRowsetRefreshFALSE)
|
|
{
|
|
fOverWrite=FALSE;
|
|
}
|
|
|
|
//For each method of the interface, first create an error object on
|
|
//the current thread, then try get S_OK from the IRowsetResynch method.
|
|
//We then check extended errors to verify nothing is set since an
|
|
//error object shouldn't exist following a successful call.
|
|
|
|
//Get an hRow
|
|
if (CHECK(m_hr = m_pROIRowset->GetNextRows(NULL, 0, 1, &cRowsObtained, &phRow), S_OK))
|
|
{
|
|
//create an error object
|
|
m_pExtError->CauseError();
|
|
|
|
if (CHECK(m_pROIRowset->GetData(hRow, m_hROAccessor, m_pRowsetData), S_OK))
|
|
{
|
|
//create an error object
|
|
m_pExtError->CauseError();
|
|
|
|
//call ResynchRows, try last three params as NULL for variety
|
|
if (CHECK(hr=ResynchRefresh(DB_NULL_HCHAPTER,1, phRow, fOverWrite,NULL, NULL, NULL,TRUE), S_OK))
|
|
{
|
|
if (m_eTI==TI_IRowsetResynch)
|
|
{
|
|
//Do extended check following ResynchRows
|
|
fResults &= XCHECK(m_pROIRowsetResynch, IID_IRowsetResynch, hr);
|
|
}
|
|
else
|
|
{
|
|
//Do extended check following ResynchRows
|
|
fResults &= XCHECK(m_pROIRowsetRefresh, IID_IRowsetRefresh, hr);
|
|
}
|
|
|
|
if (CHECK(m_pROIRowset->GetData(hRow, m_hROAccessor, m_pResynchRowsetData), S_OK))
|
|
{
|
|
//Call method GetVisibleData
|
|
if (CHECK(GetLastVisibleData(*phRow,m_hROAccessor,m_pResynchVisibleData,TRUE), S_OK))
|
|
{
|
|
if (m_eTI==TI_IRowsetResynch)
|
|
{
|
|
//Do extended check following GetVisibleData
|
|
fResults = XCHECK(m_pROIRowsetResynch, IID_IRowsetResynch, hr);
|
|
}
|
|
else
|
|
{
|
|
//Do extended check following GetVisibleData
|
|
fResults = XCHECK(m_pROIRowsetRefresh, IID_IRowsetRefresh, hr);
|
|
}
|
|
//There should be no new values found here, since we
|
|
//didn't do a change on the other rowset, so expect
|
|
//the first row in the rowset to always be returned
|
|
//if (!VerifyData(VERIFY_OLD, VERIFY_OLD, VERIFY_OLD, GetNextRowToDelete()))
|
|
if (!VerifyData(VERIFY_OLD, VERIFY_IGNORE, VERIFY_OLD, VERIFY_OLD, g_ulFirstRowInTable))
|
|
{
|
|
fResults = FALSE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (hRow != DB_NULL_HROW)
|
|
m_pROIRowset->ReleaseRows(1, &hRow, NULL, NULL, NULL);
|
|
|
|
if (fResults)
|
|
return TEST_PASS;
|
|
else
|
|
return TEST_FAIL;
|
|
}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(2)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc Invalid GetVisibleData call with previous error object existing
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCExtendedErrorsResynch::Variation_2()
|
|
{
|
|
HROW hRow = DB_NULL_HROW;
|
|
HROW *phRow = &hRow;
|
|
BOOL fResults = FALSE;
|
|
HRESULT hr;
|
|
DBCOUNTITEM cRowsObtained = 0;
|
|
|
|
//For each method of the interface, first create an error object on
|
|
//the current thread, then try get a failure from the GetVisibleData method.
|
|
//We then check extended errors to verify the right extended error behavior.
|
|
|
|
//Get an hRow
|
|
if (CHECK(m_hr = m_pROIRowset->GetNextRows(NULL, 0, 1, &cRowsObtained, &phRow), S_OK))
|
|
{
|
|
//create an error object
|
|
m_pExtError->CauseError();
|
|
|
|
//Call method with a NULL pData
|
|
if (CHECK(hr=GetLastVisibleData(*phRow, NULL, m_pVisibleData,TRUE), DB_E_BADACCESSORHANDLE))
|
|
{
|
|
if (m_eTI==TI_IRowsetResynch)
|
|
{
|
|
//Do extended check following GetVisibleData
|
|
fResults = XCHECK(m_pROIRowsetResynch, IID_IRowsetResynch, hr);
|
|
}
|
|
else
|
|
{
|
|
//Do extended check following GetVisibleData
|
|
fResults = XCHECK(m_pROIRowsetRefresh, IID_IRowsetRefresh, hr);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (hRow != DB_NULL_HROW)
|
|
m_pROIRowset->ReleaseRows(1, &hRow, NULL, NULL, NULL);
|
|
|
|
if (fResults)
|
|
return TEST_PASS;
|
|
else
|
|
return TEST_FAIL;
|
|
|
|
}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(3)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc Invalid ResynchRows call with previous error object existing
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCExtendedErrorsResynch::Variation_3()
|
|
{
|
|
HRESULT hr;
|
|
BOOL fTest = FALSE;
|
|
BOOL fOverWrite = TRUE;
|
|
|
|
if (m_eTI==TI_IRowsetRefreshFALSE)
|
|
{
|
|
fOverWrite=FALSE;
|
|
}
|
|
|
|
//For each method of the interface, first create an error object on
|
|
//the current thread, then try get a failure from the ResynchRows method.
|
|
//We then check extended errors to verify the right extended error behavior.
|
|
|
|
//create an error object
|
|
m_pExtError->CauseError();
|
|
|
|
m_cRowsResynched = 5;
|
|
m_rghRowsResynched = (HROW *)JUNK_PTR;
|
|
m_rgRowStatus = (DBROWSTATUS *)JUNK_PTR;
|
|
|
|
//All valid args except rghRows
|
|
if (CHECK(hr=ResynchRefresh(DB_NULL_HCHAPTER,1, NULL, fOverWrite, &m_cRowsResynched,&m_rghRowsResynched, &m_rgRowStatus,FALSE), E_INVALIDARG))
|
|
{
|
|
//error so these have to be zero and NULL and NULL
|
|
if (m_cRowsResynched || m_rghRowsResynched || m_rgRowStatus)
|
|
{
|
|
FreeOutParams();
|
|
goto CLEANUP;
|
|
}
|
|
if(m_eTI==TI_IRowsetResynch)
|
|
{
|
|
//Do extended check following ResynchRows
|
|
fTest = XCHECK(m_pChgIRowsetResynch, IID_IRowsetResynch, hr);
|
|
}
|
|
else
|
|
{
|
|
//Do extended check following ResynchRows
|
|
fTest = XCHECK(m_pChgIRowsetRefresh, IID_IRowsetRefresh, hr);
|
|
}
|
|
FreeOutParams();
|
|
}
|
|
CLEANUP:
|
|
if(fTest)
|
|
{
|
|
return TRUE;
|
|
}
|
|
else
|
|
{
|
|
return FALSE;
|
|
}
|
|
}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(4)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc Invalid IRowsetResynch calls no with previous error object existing
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCExtendedErrorsResynch::Variation_4()
|
|
{
|
|
HROW hRow = DB_NULL_HROW;
|
|
HRESULT hr;
|
|
BOOL fTest = FALSE;
|
|
BOOL fOverWrite = TRUE;
|
|
|
|
if (m_eTI==TI_IRowsetRefreshFALSE)
|
|
{
|
|
fOverWrite=FALSE;
|
|
}
|
|
|
|
//For each method of the interface, with no error object on
|
|
//the current thread, try get a failure from the IRowsetResynch method.
|
|
//We then check extended errors to verify the right extended error behavior.
|
|
|
|
m_cRowsResynched = 5;
|
|
m_rghRowsResynched = (HROW *)JUNK_PTR;
|
|
m_rgRowStatus = (DBROWSTATUS *)JUNK_PTR;
|
|
|
|
if (CHECK(hr=ResynchRefresh(DB_NULL_HCHAPTER,1, &hRow, fOverWrite, &m_cRowsResynched,&m_rghRowsResynched, &m_rgRowStatus, FALSE), DB_E_ERRORSOCCURRED))
|
|
{
|
|
COMPARE(m_cRowsResynched,1);
|
|
COMPARE(m_rghRowsResynched[0],DB_NULL_HROW);
|
|
CompareOutParams(1, &hRow);
|
|
|
|
//Do extended check following ResynchRows
|
|
if(m_eTI==TI_IRowsetResynch)
|
|
{
|
|
//Do extended check following ResynchRows
|
|
fTest &= XCHECK(m_pChgIRowsetResynch, IID_IRowsetResynch, hr);
|
|
}
|
|
else
|
|
{
|
|
//Do extended check following ResynchRows
|
|
fTest &= XCHECK(m_pChgIRowsetRefresh, IID_IRowsetRefresh, hr);
|
|
}
|
|
|
|
if (!COMPARE(m_rgRowStatus[0], DBROWSTATUS_E_INVALID))
|
|
fTest &= FALSE;
|
|
}
|
|
//Note, provider not required to check for this return code
|
|
if (CHECK(hr=GetLastVisibleData(hRow, m_hChgAccessor, m_pVisibleData,FALSE), DB_E_BADROWHANDLE))
|
|
{
|
|
//Do extended check following GetVisibleData
|
|
if(m_eTI==TI_IRowsetResynch)
|
|
{
|
|
//Do extended check following ResynchRows
|
|
fTest = XCHECK(m_pChgIRowsetResynch, IID_IRowsetResynch, hr);
|
|
}
|
|
else
|
|
{
|
|
//Do extended check following ResynchRows
|
|
fTest = XCHECK(m_pChgIRowsetRefresh, IID_IRowsetRefresh, hr);
|
|
}
|
|
}
|
|
FreeOutParams();
|
|
|
|
if(fTest)
|
|
return TRUE;
|
|
else
|
|
return FALSE;
|
|
}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(5)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc Invalid ResynchRows - E_INVALIDARG
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCExtendedErrorsResynch::Variation_5()
|
|
{
|
|
HRESULT hr;
|
|
BOOL fTest = FALSE;
|
|
DBCOUNTITEM cRowsObtained = 0;
|
|
HROW hRow = DB_NULL_HROW;
|
|
HROW *phRow = &hRow;
|
|
BOOL fOverWrite = TRUE;
|
|
|
|
if (m_eTI==TI_IRowsetRefreshFALSE)
|
|
{
|
|
fOverWrite=FALSE;
|
|
}
|
|
|
|
//Get an hRow
|
|
if (CHECK(m_hr = m_pROIRowset->GetNextRows(NULL, 0, 1, &cRowsObtained, &phRow), S_OK))
|
|
{
|
|
//pcRowsRefreshed was not a null pointer, and prghRowsRefreshed was a null pointer
|
|
if (CHECK(hr=ResynchRefresh(DB_NULL_HCHAPTER,1, phRow, fOverWrite, &m_cRowsResynched,NULL, NULL, FALSE), E_INVALIDARG))
|
|
{
|
|
//error so these have to be zero and NULL and NULL
|
|
if (m_cRowsResynched)
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
//Do extended check following ResynchRows
|
|
if(m_eTI==TI_IRowsetResynch)
|
|
{
|
|
//Do extended check following ResynchRows
|
|
fTest = XCHECK(m_pChgIRowsetResynch, IID_IRowsetResynch, hr);
|
|
}
|
|
else
|
|
{
|
|
//Do extended check following ResynchRows
|
|
fTest = XCHECK(m_pChgIRowsetRefresh, IID_IRowsetRefresh, hr);
|
|
}
|
|
}
|
|
}
|
|
CLEANUP:
|
|
if (hRow != DB_NULL_HROW)
|
|
{
|
|
m_pROIRowset->ReleaseRows(1, &hRow, NULL, NULL, NULL);
|
|
}
|
|
if(fTest)
|
|
{
|
|
return TRUE;
|
|
}
|
|
else
|
|
{
|
|
return FALSE;
|
|
}
|
|
}
|
|
// }}
|
|
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(6)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc pcRowsRefreshed - NULL, ignore prghRowsRefreshed
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCExtendedErrorsResynch::Variation_6()
|
|
{
|
|
HRESULT hr;
|
|
ULONG cRowsObtained = 0;
|
|
BOOL fOverWrite = TRUE;
|
|
HROW *pJunkHRow = (HROW *)JUNK_PTR;
|
|
|
|
if (m_eTI==TI_IRowsetRefreshFALSE)
|
|
{
|
|
fOverWrite=FALSE;
|
|
}
|
|
|
|
//All valid args. prghRowsRefreshed is junk but is ignored when pcRowsRefreshed is NULL
|
|
if (CHECK(hr=ResynchRefresh(DB_NULL_HCHAPTER,0, NULL, fOverWrite, NULL,&pJunkHRow, NULL, TRUE), S_OK))
|
|
{
|
|
return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
// }}
|
|
|
|
|
|
|
|
// {{ TCW_TERMINATE_METHOD
|
|
//--------------------------------------------------------------------
|
|
// @mfunc TestCase Termination Routine
|
|
//
|
|
// @rdesc TRUE or FALSE
|
|
//
|
|
BOOL TCExtendedErrorsResynch::Terminate()
|
|
{
|
|
//if (m_pExtError)
|
|
// delete m_pExtError;
|
|
//m_pExtError = NULL;
|
|
|
|
return(CResynchRefresh::Terminate());
|
|
|
|
} // }}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_TC_PROTOTYPE(TCPropResynchOnlyResynch)
|
|
//*-----------------------------------------------------------------------
|
|
//| Test Case: TCPropResynchOnlyResynch - Rowsets with only IRowsetResynch Requested
|
|
//| Created: 07/26/96
|
|
//*-----------------------------------------------------------------------
|
|
|
|
//--------------------------------------------------------------------
|
|
// @mfunc TestCase Initialization Routine
|
|
//
|
|
// @rdesc TRUE or FALSE
|
|
//
|
|
BOOL TCPropResynchOnlyResynch::Init()
|
|
{
|
|
const ULONG cProps = 3;
|
|
DBPROP rgProps[cProps];
|
|
DBPROPSET DBPropSet;
|
|
|
|
if (TEST_SKIPPED==fnInterfaceSupported())
|
|
{
|
|
return TEST_SKIPPED;
|
|
}
|
|
|
|
if (m_eTI==TI_IRowsetResynch)
|
|
{
|
|
rgProps[0].dwPropertyID = DBPROP_IRowsetResynch;
|
|
rgProps[0].dwOptions = 0;
|
|
rgProps[0].colid = DB_NULLID;
|
|
rgProps[0].vValue.vt = VT_BOOL;
|
|
V_BOOL(&(rgProps[0].vValue)) = VARIANT_TRUE;
|
|
}
|
|
else
|
|
{
|
|
rgProps[0].dwPropertyID = DBPROP_IRowsetRefresh;
|
|
rgProps[0].dwOptions = 0;
|
|
rgProps[0].colid = DB_NULLID;
|
|
rgProps[0].vValue.vt = VT_BOOL;
|
|
V_BOOL(&(rgProps[0].vValue)) = VARIANT_TRUE;
|
|
}
|
|
|
|
rgProps[1].dwPropertyID = DBPROP_IRowsetChange;
|
|
rgProps[1].dwOptions = 0;
|
|
rgProps[1].colid = DB_NULLID;
|
|
rgProps[1].vValue.vt = VT_BOOL;
|
|
V_BOOL(&(rgProps[1].vValue)) = VARIANT_TRUE;
|
|
|
|
rgProps[2].dwPropertyID = DBPROP_UPDATABILITY;
|
|
rgProps[2].dwOptions = 0;
|
|
rgProps[2].colid = DB_NULLID;
|
|
rgProps[2].vValue.vt = VT_I4;
|
|
rgProps[2].vValue.lVal = DBPROPVAL_UP_CHANGE | DBPROPVAL_UP_DELETE | DBPROPVAL_UP_INSERT;
|
|
|
|
DBPropSet.rgProperties = rgProps;
|
|
DBPropSet.cProperties = 1; //Use only the first prop in the array for the first rowset
|
|
DBPropSet.guidPropertySet = DBPROPSET_ROWSET;
|
|
|
|
// {{ TCW_INIT_BASECLASS_CHECK
|
|
if(CResynchRefresh::Init(m_eTI))
|
|
// }}
|
|
{
|
|
//Release command objects so properties are wiped out
|
|
ReleaseResynchObjects();
|
|
m_pRORowset1->ReleaseCommandObject();
|
|
m_pChgRowset1->ReleaseCommandObject();
|
|
|
|
//Set only property IRowsetResynch for read only rowset
|
|
m_pRORowset1->SetRowsetProperties(&DBPropSet, 1);
|
|
//Add changeable props also for this rowset
|
|
DBPropSet.cProperties = cProps;
|
|
m_pChgRowset1->SetRowsetProperties(&DBPropSet, 1);
|
|
|
|
return CreateResynchObjects(m_eTI);
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(1)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc Read only rowset with Resynch Only
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCPropResynchOnlyResynch::Variation_1()
|
|
{
|
|
ReleaseResynchObjects();
|
|
if (!COMPARE(CreateResynchObjects(m_eTI), TRUE))
|
|
{
|
|
return FALSE;
|
|
}
|
|
return TestResynchRefresh(EREADONLY);
|
|
}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(2)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc Changeable rowset with Resynch Only
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCPropResynchOnlyResynch::Variation_2()
|
|
{
|
|
ReleaseResynchObjects();
|
|
if (!COMPARE(CreateResynchObjects(m_eTI), TRUE))
|
|
{
|
|
return FALSE;
|
|
}
|
|
return TestResynchRefresh(ECHANGEABLE);
|
|
}
|
|
// {{ TCW_TERMINATE_METHOD
|
|
//--------------------------------------------------------------------
|
|
// @mfunc TestCase Termination Routine
|
|
//
|
|
// @rdesc TRUE or FALSE
|
|
//
|
|
BOOL TCPropResynchOnlyResynch::Terminate()
|
|
{
|
|
// TO DO: Add your own code here
|
|
|
|
// {{ TCW_TERM_BASECLASS_CHECK2
|
|
return(CResynchRefresh::Terminate());
|
|
}
|
|
|
|
|
|
// {{ TCW_TC_PROTOTYPE(TCPropCanHoldRowsResynchBLOBS)
|
|
//*-----------------------------------------------------------------------
|
|
//| Test Case: TCPropCanHoldRowsResynchBLOBS - CanHoldRows testcases using BLOB data
|
|
//| Created: 08/14/96
|
|
//*-----------------------------------------------------------------------
|
|
|
|
//--------------------------------------------------------------------
|
|
// @mfunc TestCase Initialization Routine
|
|
//
|
|
// @rdesc TRUE or FALSE
|
|
//
|
|
BOOL TCPropCanHoldRowsResynchBLOBS::Init()
|
|
{
|
|
DBPROP PropLocate;
|
|
|
|
if (TEST_SKIPPED==fnInterfaceSupported())
|
|
{
|
|
return TEST_SKIPPED;
|
|
}
|
|
|
|
PropLocate.dwPropertyID = DBPROP_IRowsetLocate;
|
|
PropLocate.dwOptions = DBPROPOPTIONS_REQUIRED;
|
|
PropLocate.colid = DB_NULLID;
|
|
PropLocate.vValue.vt = VT_BOOL;
|
|
V_BOOL(&(PropLocate.vValue)) = VARIANT_TRUE;
|
|
|
|
//Set this so that Init knows we want to try for blob columns
|
|
m_fRequestLongDataIfSupported = TRUE;
|
|
|
|
// {{ TCW_INIT_BASECLASS_CHECK
|
|
if(CPropCanHoldRowsResynch::Init(m_eTI))
|
|
// }}
|
|
{
|
|
//Find highest isolation level
|
|
if (m_fSerializable)
|
|
{
|
|
m_fHighestSupportedIsoLevel = ISOLATIONLEVEL_SERIALIZABLE;
|
|
}
|
|
else
|
|
{
|
|
if (m_fRepeatableRead)
|
|
{
|
|
m_fHighestSupportedIsoLevel = ISOLATIONLEVEL_REPEATABLEREAD;
|
|
}
|
|
else
|
|
{
|
|
if (m_fReadCommitted)
|
|
{
|
|
m_fHighestSupportedIsoLevel = ISOLATIONLEVEL_READCOMMITTED;
|
|
}
|
|
else
|
|
{
|
|
if (m_fReadUncommitted)
|
|
{
|
|
m_fHighestSupportedIsoLevel = ISOLATIONLEVEL_READUNCOMMITTED;
|
|
}
|
|
else
|
|
{
|
|
m_fHighestSupportedIsoLevel = ISOLATIONLEVEL_CHAOS;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//Add IRowsetLocate as a requested property, this
|
|
//should cause our CreateResynchObjects routine
|
|
//to always bind BLOBS, which is what we want to test
|
|
return ChangeProperties(1, &PropLocate, 0, NULL, NULL, TRUE);
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(1)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc Isolation Level - Chaos
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCPropCanHoldRowsResynchBLOBS::Variation_1()
|
|
{
|
|
BOOL fResults = FALSE;
|
|
|
|
//If no provider support for this isolation level, just return pass
|
|
if (!m_fChaos)
|
|
{
|
|
odtLog << wszNoProviderSupport << L"CHAOS" << wszNewLine;
|
|
return TEST_PASS;
|
|
}
|
|
|
|
//Not all drivers allow starting a txn with rowsets
|
|
//open, so release them before starting a txn
|
|
ReleaseResynchObjects();
|
|
|
|
//Start txn we're testing at Chaos Isolation Level
|
|
if (CHECK(m_pRORowset1->m_pITxnLocal->StartTransaction(ISOLATIONLEVEL_CHAOS, 0, NULL, NULL), S_OK))
|
|
{
|
|
if (CreateResynchObjects(m_eTI))
|
|
{
|
|
if (GenerateResynchData(m_pRORowset1, ISOLATIONLEVEL_CHAOS, m_hROAccessor))
|
|
{
|
|
//the rowset is ignore cause the blob might or might not forect the GetData to go to the back end
|
|
if (VerifyData(VERIFY_NEW,VERIFY_NEW,VERIFY_IGNORE,VERIFY_NEW))
|
|
{
|
|
//Everything went OK
|
|
fResults = TRUE;
|
|
}
|
|
}
|
|
}
|
|
COMPARE(EndTxns(), TRUE);
|
|
}
|
|
FreeOutParams();
|
|
if (fResults)
|
|
return TEST_PASS;
|
|
else
|
|
return TEST_FAIL;
|
|
}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(2)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc Isolation Level - Read Uncommitted
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCPropCanHoldRowsResynchBLOBS::Variation_2()
|
|
{
|
|
BOOL fResults = FALSE;
|
|
|
|
//If no provider support for this isolation level, just return pass
|
|
if (!m_fReadUncommitted)
|
|
{
|
|
odtLog << wszNoProviderSupport << L"READUNCOMMITTED" << wszNewLine;
|
|
return TEST_PASS;
|
|
}
|
|
|
|
//Not all drivers allow starting a txn with rowsets
|
|
//open, so release them before starting a txn
|
|
ReleaseResynchObjects();
|
|
|
|
//Start txn we're testing at Read Uncommitted Isolation Level
|
|
if (CHECK(m_pRORowset1->m_pITxnLocal->StartTransaction(ISOLATIONLEVEL_READUNCOMMITTED, 0, NULL, NULL), S_OK))
|
|
{
|
|
if (CreateResynchObjects(m_eTI))
|
|
{
|
|
if (GenerateResynchData(m_pRORowset1, ISOLATIONLEVEL_READUNCOMMITTED, m_hROAccessor))
|
|
{
|
|
//the rowset is ignore cause the blob might or might not forect the GetData to go to the back end
|
|
if (VerifyData(VERIFY_NEW,VERIFY_NEW,VERIFY_IGNORE,VERIFY_NEW))
|
|
{
|
|
//Everything went OK
|
|
fResults = TRUE;
|
|
}
|
|
}
|
|
}
|
|
COMPARE(EndTxns(), TRUE);
|
|
}
|
|
FreeOutParams();
|
|
if (fResults)
|
|
return TEST_PASS;
|
|
else
|
|
return TEST_FAIL;
|
|
}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(3)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc Isolation Level - Read Committed
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCPropCanHoldRowsResynchBLOBS::Variation_3()
|
|
{
|
|
BOOL fResults = FALSE;
|
|
|
|
//If no provider support for this isolation level, just return pass
|
|
if (!m_fReadCommitted)
|
|
{
|
|
odtLog << wszNoProviderSupport << L"READCOMMITTED" << wszNewLine;
|
|
return TEST_PASS;
|
|
}
|
|
|
|
//Not all drivers allow starting a txn with rowsets
|
|
//open, so release them before starting a txn
|
|
ReleaseResynchObjects();
|
|
|
|
//Start txn we're testing at Read Committed Isolation Level
|
|
if (CHECK(StartTxns(ISOLATIONLEVEL_READCOMMITTED), S_OK))
|
|
{
|
|
if (CreateResynchObjects(m_eTI))
|
|
{
|
|
if (GenerateResynchData(m_pChgRowset1, ISOLATIONLEVEL_READCOMMITTED, m_hChgAccessor))
|
|
{
|
|
if (VerifyData(VERIFY_OLD,VERIFY_OLD,VERIFY_OLD,VERIFY_OLD))
|
|
{
|
|
//Now do the same thing on our read only rowset
|
|
if (GenerateResynchData(m_pRORowset1, ISOLATIONLEVEL_READCOMMITTED, m_hROAccessor))
|
|
{
|
|
if (VerifyData(VERIFY_OLD,VERIFY_OLD,VERIFY_OLD,VERIFY_OLD))
|
|
{
|
|
//Everything went OK
|
|
fResults = TRUE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
COMPARE(EndTxns(), TRUE);
|
|
}
|
|
FreeOutParams();
|
|
if (fResults)
|
|
return TEST_PASS;
|
|
else
|
|
return TEST_FAIL;
|
|
}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(4)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc Isolation Level - Repeatable Read
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCPropCanHoldRowsResynchBLOBS::Variation_4()
|
|
{
|
|
BOOL fResults = FALSE;
|
|
|
|
//If no provider support for this isolation level, just return pass
|
|
if (!m_fRepeatableRead)
|
|
{
|
|
odtLog << wszNoProviderSupport << L"REPEATABLEREAD" << wszNewLine;
|
|
return TEST_PASS;
|
|
|
|
}
|
|
|
|
//Not all drivers allow starting a txn with rowsets
|
|
//open, so release them before starting a txn
|
|
ReleaseResynchObjects();
|
|
|
|
//Start txn we're testing at Read Repeated Isolation Level
|
|
if (CHECK(StartTxns(ISOLATIONLEVEL_REPEATABLEREAD), S_OK))
|
|
{
|
|
if (CreateResynchObjects(m_eTI))
|
|
{
|
|
//Test visible data on our changeable rowset
|
|
//TODO: Since Long data isn't necessarily transacted on the server
|
|
//we should ignore the long data check the fixed data. Need
|
|
//to find out more details on how the server does this
|
|
if (GenerateResynchData(m_pChgRowset1, ISOLATIONLEVEL_REPEATABLEREAD, m_hChgAccessor))
|
|
{
|
|
if (VerifyData(VERIFY_OLD,VERIFY_OLD,VERIFY_OLD,VERIFY_OLD))
|
|
{
|
|
//Now do the same thing on our read only rowset
|
|
if (GenerateResynchData(m_pRORowset1, ISOLATIONLEVEL_REPEATABLEREAD, m_hROAccessor))
|
|
{
|
|
if (VerifyData(VERIFY_OLD,VERIFY_OLD,VERIFY_OLD,VERIFY_OLD))
|
|
{
|
|
//Everything went OK
|
|
fResults = TRUE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
EndTxns();
|
|
}
|
|
FreeOutParams();
|
|
if (fResults)
|
|
return TEST_PASS;
|
|
else
|
|
return TEST_FAIL;
|
|
}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(5)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc Isolation Level - Serializable
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCPropCanHoldRowsResynchBLOBS::Variation_5()
|
|
{
|
|
BOOL fResults = FALSE;
|
|
|
|
//If no provider support for this isolation level, just return pass
|
|
if (!m_fSerializable)
|
|
{
|
|
odtLog << wszNoProviderSupport << L"SERIALIZABLE" << wszNewLine;
|
|
return TEST_PASS;
|
|
|
|
}
|
|
|
|
//Not all drivers allow starting a txn with rowsets
|
|
//open, so release them before starting a txn
|
|
ReleaseResynchObjects();
|
|
|
|
//Start txn we're testing at Serializable Isolation Level
|
|
if (CHECK(StartTxns(ISOLATIONLEVEL_SERIALIZABLE), S_OK))
|
|
{
|
|
if (CreateResynchObjects(m_eTI))
|
|
{
|
|
//Test visible data on our changeable rowset
|
|
//TODO: Since long data isn't transacted on the server,
|
|
//should just ignore long data but still check fixed data.
|
|
if (GenerateResynchData(m_pChgRowset1, ISOLATIONLEVEL_SERIALIZABLE, m_hChgAccessor))
|
|
{
|
|
if (VerifyData(VERIFY_OLD,VERIFY_OLD,VERIFY_OLD,VERIFY_OLD))
|
|
{
|
|
//Now do the same thing on our read only rowset
|
|
if (GenerateResynchData(m_pRORowset1, ISOLATIONLEVEL_SERIALIZABLE, m_hROAccessor))
|
|
{
|
|
if (VerifyData(VERIFY_OLD,VERIFY_OLD,VERIFY_OLD,VERIFY_OLD))
|
|
{
|
|
//Everything went OK
|
|
fResults = TRUE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
COMPARE(EndTxns(), TRUE);
|
|
}
|
|
FreeOutParams();
|
|
if (fResults)
|
|
return TEST_PASS;
|
|
else
|
|
return TEST_FAIL;
|
|
}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(6)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc Isolation Level - Unspecified
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCPropCanHoldRowsResynchBLOBS::Variation_6()
|
|
{
|
|
BOOL fResults = FALSE;
|
|
|
|
//Start txn we're testing at unspecified Isolation Level
|
|
if (CHECK(StartTxns(ISOLATIONLEVEL_UNSPECIFIED), XACT_E_ISOLATIONLEVEL))
|
|
{
|
|
//Everything went OK
|
|
fResults = TRUE;
|
|
}
|
|
|
|
//in case a txn was started
|
|
COMPARE(EndTxns(), TRUE);
|
|
|
|
if (fResults)
|
|
return TEST_PASS;
|
|
else
|
|
return TEST_FAIL;
|
|
}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(7)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc Own Insert - Highest Isolation Level
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCPropCanHoldRowsResynchBLOBS::Variation_7()
|
|
{
|
|
BOOL fResults = FALSE;
|
|
HROW hRow = DB_NULL_HROW;
|
|
ULONG cRowsObtained = 0;
|
|
HRESULT ExpectedHr;
|
|
BOOL fOverWrite = TRUE;
|
|
|
|
if (m_eTI==TI_IRowsetRefreshFALSE)
|
|
{
|
|
fOverWrite=FALSE;
|
|
}
|
|
|
|
//If no provider support for this isolation level, just return pass
|
|
if (!m_fChaos && !m_fReadUncommitted && !m_fReadCommitted &&
|
|
!m_fRepeatableRead && !m_fSerializable)
|
|
{
|
|
odtLog << wszNoProviderSupport << L"ANY" << wszNewLine;
|
|
return TEST_PASS;
|
|
}
|
|
|
|
//Not all drivers allow starting a txn with rowsets
|
|
//open, so release them before starting a txn
|
|
ReleaseResynchObjects();
|
|
|
|
//Set the highest possible isolation level, to make this test interesting
|
|
//since regardless of isolation, we should always see our own insert.
|
|
//Note that we only start a txn for this rowset and not the RORowset,
|
|
//since otherwise the RORowset could lock us from inserting
|
|
//due to the high isolation level
|
|
if (!CHECK(m_pChgRowset1->m_pITxnLocal->StartTransaction(m_fHighestSupportedIsoLevel, 0, NULL, NULL), S_OK))
|
|
goto CLEANUP;
|
|
|
|
if (!COMPARE(CreateResynchObjects(m_eTI), TRUE))
|
|
goto CLEANUP;
|
|
|
|
//Insert new row ourselves and keep hRow
|
|
if (!COMPARE(m_pChgRowset1->Insert(GetNextRowToInsert(), &hRow), TRUE))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
//increment for comparasion
|
|
g_ulLastActualInsert++;
|
|
|
|
//If we don't support strong identity, our single row will fail
|
|
if (m_fStrongIdentity)
|
|
{
|
|
ExpectedHr = S_OK;
|
|
}
|
|
else
|
|
{
|
|
ExpectedHr = DB_E_ERRORSOCCURRED;
|
|
}
|
|
|
|
m_cRowsResynched = 5;
|
|
m_rghRowsResynched = (HROW *)JUNK_PTR;
|
|
m_rgRowStatus = (DBROWSTATUS *)JUNK_PTR;
|
|
|
|
//Now do a ResynchRows to see if new data is brought in
|
|
if (!CHECK(ResynchRefresh(DB_NULL_HCHAPTER,1, &hRow, fOverWrite, &m_cRowsResynched, &m_rghRowsResynched, &m_rgRowStatus, FALSE), ExpectedHr))
|
|
{
|
|
FreeOutParams();
|
|
goto CLEANUP;
|
|
}
|
|
|
|
//This only applies if we support resynch on this newly inserted row
|
|
//This only applies if we support resynch on this newly inserted row
|
|
if (m_fStrongIdentity)
|
|
{
|
|
//Now Get Newly Resynch'd Data
|
|
if (!CHECK(m_pChgIRowset->GetData(hRow, m_hChgAccessor, m_pResynchRowsetData), S_OK))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
|
|
//Now GetVisibleData on the same row
|
|
if (!CHECK(GetLastVisibleData(hRow, m_hChgAccessor, m_pResynchVisibleData,FALSE), S_OK))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
|
|
//refresh should bring in the defaults
|
|
|
|
//Now make sure we could see the new data at all times, since its our own insert
|
|
if (VerifyData(VERIFY_NEW, VERIFY_IGNORE, VERIFY_IGNORE, VERIFY_NEW))
|
|
{
|
|
//Everything went OK
|
|
fResults = TRUE;
|
|
}
|
|
}
|
|
//Make sure our status is right
|
|
else
|
|
{
|
|
COMPARE(m_cRowsResynched,1);
|
|
COMPARE(m_rghRowsResynched[0],hRow);
|
|
CompareOutParams(1, &hRow);
|
|
fResults = COMPARE(m_rgRowStatus[0], DBROWSTATUS_E_NEWLYINSERTED);
|
|
}
|
|
FreeOutParams();
|
|
fResults = TEST_PASS;
|
|
CLEANUP:
|
|
if (5!=m_cRowsResynched)
|
|
{
|
|
FreeOutParams();
|
|
}
|
|
if (hRow != DB_NULL_HROW)
|
|
m_pChgIRowset->ReleaseRows(1, &hRow, NULL, NULL, NULL);
|
|
|
|
//back out changes
|
|
COMPARE(EndTxns(TRUE), TRUE);
|
|
g_ulLastActualInsert--;
|
|
|
|
if (fResults)
|
|
return TEST_PASS;
|
|
else
|
|
return TEST_FAIL;
|
|
}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(8)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc Variable Length Columns Only Bound
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCPropCanHoldRowsResynchBLOBS::Variation_8()
|
|
{
|
|
BOOL fResults = FALSE;
|
|
HACCESSOR hChgAccessor = DB_NULL_HACCESSOR;
|
|
HACCESSOR hROAccessor = DB_NULL_HACCESSOR;
|
|
DBBINDING *rgBindings = NULL;
|
|
DBCOUNTITEM cBindings = 0;
|
|
|
|
ReleaseResynchObjects();
|
|
if (!COMPARE(CreateResynchObjects(m_eTI), TRUE))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
//Get accessors with only variable length bound. Bindings will be the same
|
|
//for changeable and read only rowsets
|
|
if (!CHECK(GetAccessorAndBindings(m_pChgRowset1->m_pIAccessor, DBACCESSOR_ROWDATA,
|
|
&hChgAccessor, &rgBindings, &cBindings, NULL,
|
|
DBPART_VALUE | DBPART_LENGTH | DBPART_STATUS,
|
|
VARIABLE_LEN_COLS_BOUND,
|
|
FORWARD, NO_COLS_BY_REF, NULL, NULL,
|
|
NULL, DBTYPE_EMPTY, 0, NULL, NULL,
|
|
NO_COLS_OWNED_BY_PROV, DBPARAMIO_NOTPARAM,
|
|
m_fBindLongData),S_OK))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
if (!CHECK(GetAccessorAndBindings(m_pRORowset1->m_pIAccessor, DBACCESSOR_ROWDATA,
|
|
&hROAccessor, NULL, NULL, NULL,
|
|
DBPART_VALUE | DBPART_LENGTH | DBPART_STATUS,
|
|
VARIABLE_LEN_COLS_BOUND,
|
|
FORWARD, NO_COLS_BY_REF, NULL, NULL,
|
|
NULL, DBTYPE_EMPTY, 0, NULL, NULL,
|
|
NO_COLS_OWNED_BY_PROV, DBPARAMIO_NOTPARAM,
|
|
m_fBindLongData),S_OK))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
//Test visible data on our changeable rowset
|
|
if (GenerateResynchData(m_pChgRowset1, ISOLATIONLEVEL_CHAOS, hChgAccessor, rgBindings, cBindings))
|
|
{
|
|
if (VerifyData(VERIFY_NEW, VERIFY_NEW, VERIFY_IGNORE, VERIFY_NEW, 0, 0, cBindings, rgBindings))
|
|
{
|
|
//Now do the same thing on our read only rowset
|
|
if (GenerateResynchData(m_pRORowset1, ISOLATIONLEVEL_CHAOS, hROAccessor, rgBindings, cBindings))
|
|
{
|
|
if (VerifyData(VERIFY_NEW, VERIFY_NEW, VERIFY_IGNORE, VERIFY_NEW, 0, 0, cBindings, rgBindings))
|
|
{
|
|
//Everything went OK
|
|
fResults = TRUE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
CLEANUP:
|
|
FreeOutParams();
|
|
if (hChgAccessor != DB_NULL_HACCESSOR)
|
|
m_pChgRowset1->m_pIAccessor->ReleaseAccessor(hChgAccessor, NULL);
|
|
|
|
if (hROAccessor != DB_NULL_HACCESSOR)
|
|
m_pRORowset1->m_pIAccessor->ReleaseAccessor(hROAccessor, NULL);
|
|
|
|
if (rgBindings)
|
|
PROVIDER_FREE(rgBindings);
|
|
|
|
if (fResults)
|
|
return TEST_PASS;
|
|
else
|
|
return TEST_FAIL;
|
|
}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(9)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc Fixed Length Columns Only Bound
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCPropCanHoldRowsResynchBLOBS::Variation_9()
|
|
{
|
|
BOOL fResults = FALSE;
|
|
HACCESSOR hChgAccessor = DB_NULL_HACCESSOR;
|
|
HACCESSOR hROAccessor = DB_NULL_HACCESSOR;
|
|
DBBINDING *rgBindings = NULL;
|
|
DBCOUNTITEM cBindings = 0;
|
|
|
|
ReleaseResynchObjects();
|
|
if (!COMPARE(CreateResynchObjects(m_eTI), TRUE))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
//Get accessors with only fixed length bound, bindings
|
|
//are the same for changeable and RO accessors
|
|
if (!CHECK(GetAccessorAndBindings(m_pChgRowset1->m_pIAccessor, DBACCESSOR_ROWDATA,
|
|
&hChgAccessor, &rgBindings, &cBindings, NULL,
|
|
DBPART_VALUE | DBPART_LENGTH | DBPART_STATUS,
|
|
FIXED_LEN_COLS_BOUND,
|
|
FORWARD, NO_COLS_BY_REF, NULL, NULL,
|
|
NULL, DBTYPE_EMPTY, 0, NULL, NULL,
|
|
NO_COLS_OWNED_BY_PROV, DBPARAMIO_NOTPARAM,
|
|
m_fBindLongData),S_OK))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
//Test visible data on our changeable rowset
|
|
if (GenerateResynchData(m_pChgRowset1, ISOLATIONLEVEL_CHAOS, hChgAccessor, rgBindings, cBindings))
|
|
{
|
|
if (VerifyData(VERIFY_NEW, VERIFY_NEW, VERIFY_IGNORE, VERIFY_NEW, 0, 0, cBindings, rgBindings))
|
|
{
|
|
ReleaseResynchObjects();
|
|
if (!COMPARE(CreateResynchObjects(m_eTI), TRUE))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
if (!CHECK(GetAccessorAndBindings(m_pRORowset1->m_pIAccessor, DBACCESSOR_ROWDATA,
|
|
&hROAccessor, NULL, NULL, NULL,
|
|
DBPART_VALUE | DBPART_LENGTH | DBPART_STATUS,
|
|
FIXED_LEN_COLS_BOUND,
|
|
FORWARD, NO_COLS_BY_REF, NULL, NULL,
|
|
NULL, DBTYPE_EMPTY, 0, NULL, NULL,
|
|
NO_COLS_OWNED_BY_PROV, DBPARAMIO_NOTPARAM,
|
|
m_fBindLongData),S_OK))
|
|
{
|
|
FreeOutParams();
|
|
goto CLEANUP;
|
|
} //Now do the same thing on our read only rowset
|
|
if (GenerateResynchData(m_pRORowset1, ISOLATIONLEVEL_CHAOS, hROAccessor, rgBindings, cBindings))
|
|
{
|
|
if (VerifyData(VERIFY_NEW, VERIFY_NEW, VERIFY_IGNORE, VERIFY_NEW, 0, 0, cBindings, rgBindings))
|
|
{
|
|
//Everything went OK
|
|
fResults = TRUE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
CLEANUP:
|
|
FreeOutParams();
|
|
if (rgBindings)
|
|
PROVIDER_FREE(rgBindings);
|
|
|
|
if (hChgAccessor != DB_NULL_HACCESSOR)
|
|
m_pChgRowset1->m_pIAccessor->ReleaseAccessor(hChgAccessor, NULL);
|
|
if (hROAccessor != DB_NULL_HACCESSOR)
|
|
m_pRORowset1->m_pIAccessor->ReleaseAccessor(hROAccessor, NULL);
|
|
|
|
if (fResults)
|
|
return TEST_PASS;
|
|
else
|
|
return TEST_FAIL;
|
|
}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(10)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc All Columns Bound BYREF
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCPropCanHoldRowsResynchBLOBS::Variation_10()
|
|
{
|
|
BOOL fResults = FALSE;
|
|
HACCESSOR hChgAccessor = DB_NULL_HACCESSOR;
|
|
HACCESSOR hROAccessor = DB_NULL_HACCESSOR;
|
|
ULONG i;
|
|
DBBINDING *rgBindings = NULL;
|
|
DBCOUNTITEM cBindings = 0;
|
|
DBLENGTH cRowSize = 0;
|
|
|
|
//Test visible data on our changeable rowset, repeat it several times
|
|
//to flush out any potential memory leaks and stress test it
|
|
for (i = 0; i< STRESS_RESYNCH_REPS; i++)
|
|
{
|
|
ReleaseResynchObjects();
|
|
if (!COMPARE(CreateResynchObjects(m_eTI), TRUE))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
//Since some provider's only support variable length
|
|
//cols by ref, limit the accessor to these
|
|
if (!CHECK(GetAccessorAndBindings(m_pChgRowset1->m_pIAccessor,
|
|
DBACCESSOR_ROWDATA,
|
|
&hChgAccessor, &rgBindings, &cBindings, &cRowSize,
|
|
DBPART_LENGTH | DBPART_STATUS | DBPART_VALUE,
|
|
ALL_COLS_BOUND, FORWARD, VARIABLE_LEN_COLS_BY_REF,
|
|
NULL, NULL,
|
|
NULL, DBTYPE_EMPTY, 0, NULL, NULL,
|
|
NO_COLS_OWNED_BY_PROV, DBPARAMIO_NOTPARAM,
|
|
m_fBindLongData),S_OK))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
//re-create buffers with the new accesor and bindings created just above
|
|
FreeBuffers(m_cbRowSize);
|
|
AllocDataBuffers(cRowSize);
|
|
|
|
if (GenerateResynchData(m_pChgRowset1, ISOLATIONLEVEL_CHAOS, hChgAccessor, rgBindings, cBindings))
|
|
{
|
|
if (VerifyData(VERIFY_NEW, VERIFY_NEW, VERIFY_IGNORE, VERIFY_NEW, 0, 0, cBindings, rgBindings))
|
|
{
|
|
//re-re-create buffers so class functions work correctly. yes, kind of hokey
|
|
//free with Compare to take a care of byref value
|
|
CompareData( m_pChgRowset1->m_pTable->CountColumnsOnTable(), m_pChgRowset1->m_rgTableColOrds, 1,
|
|
m_pVisibleData, cBindings, rgBindings,
|
|
m_pChgRowset1->m_pTable, m_pIMalloc, PRIMARY,
|
|
FREE_ONLY
|
|
);
|
|
CompareData( m_pChgRowset1->m_pTable->CountColumnsOnTable(), m_pChgRowset1->m_rgTableColOrds, 1,
|
|
m_pRowsetData, cBindings, rgBindings,
|
|
m_pChgRowset1->m_pTable, m_pIMalloc, PRIMARY,
|
|
FREE_ONLY
|
|
);
|
|
CompareData( m_pChgRowset1->m_pTable->CountColumnsOnTable(), m_pChgRowset1->m_rgTableColOrds, 1,
|
|
m_pResynchRowsetData, cBindings, rgBindings,
|
|
m_pChgRowset1->m_pTable, m_pIMalloc, PRIMARY,
|
|
FREE_ONLY
|
|
);
|
|
CompareData( m_pChgRowset1->m_pTable->CountColumnsOnTable(), m_pChgRowset1->m_rgTableColOrds, 1,
|
|
m_pResynchVisibleData, cBindings, rgBindings,
|
|
m_pChgRowset1->m_pTable, m_pIMalloc, PRIMARY,
|
|
FREE_ONLY
|
|
);
|
|
AllocDataBuffers(m_cbRowSize);
|
|
|
|
ReleaseResynchObjects();
|
|
if (!COMPARE(CreateResynchObjects(m_eTI), TRUE))
|
|
{
|
|
FreeOutParams();
|
|
goto CLEANUP;
|
|
}
|
|
if (!CHECK(GetAccessorAndBindings(m_pRORowset1->m_pIAccessor,
|
|
DBACCESSOR_ROWDATA,
|
|
&hROAccessor, NULL, NULL, NULL,
|
|
DBPART_LENGTH | DBPART_STATUS | DBPART_VALUE,
|
|
ALL_COLS_BOUND, FORWARD, VARIABLE_LEN_COLS_BY_REF,
|
|
NULL, NULL,
|
|
NULL, DBTYPE_EMPTY, 0, NULL, NULL,
|
|
NO_COLS_OWNED_BY_PROV, DBPARAMIO_NOTPARAM,
|
|
m_fBindLongData),S_OK))
|
|
{
|
|
FreeOutParams();
|
|
goto CLEANUP;
|
|
}
|
|
//re-create buffers with the new accesor and bindings created just above
|
|
FreeBuffers(m_cbRowSize);
|
|
AllocDataBuffers(cRowSize);
|
|
|
|
//Now do the same thing on our read only rowset
|
|
if (GenerateResynchData(m_pRORowset1, ISOLATIONLEVEL_CHAOS, hROAccessor, rgBindings, cBindings))
|
|
{
|
|
if (VerifyData(VERIFY_NEW, VERIFY_NEW, VERIFY_IGNORE, VERIFY_NEW, 0, 0, cBindings, rgBindings))
|
|
{
|
|
//Everything went OK
|
|
fResults = TRUE;
|
|
//re-re-create buffers so class functoins work correctly. yes, kind of hokey
|
|
//free with Compare to take a care of byref value
|
|
CompareData( m_pChgRowset1->m_pTable->CountColumnsOnTable(), m_pChgRowset1->m_rgTableColOrds, 1,
|
|
m_pVisibleData, cBindings, rgBindings,
|
|
m_pChgRowset1->m_pTable, m_pIMalloc, PRIMARY,
|
|
FREE_ONLY
|
|
);
|
|
CompareData( m_pChgRowset1->m_pTable->CountColumnsOnTable(), m_pChgRowset1->m_rgTableColOrds, 1,
|
|
m_pRowsetData, cBindings, rgBindings,
|
|
m_pChgRowset1->m_pTable, m_pIMalloc, PRIMARY,
|
|
FREE_ONLY
|
|
);
|
|
CompareData( m_pChgRowset1->m_pTable->CountColumnsOnTable(), m_pChgRowset1->m_rgTableColOrds, 1,
|
|
m_pResynchRowsetData, cBindings, rgBindings,
|
|
m_pChgRowset1->m_pTable, m_pIMalloc, PRIMARY,
|
|
FREE_ONLY
|
|
);
|
|
CompareData( m_pChgRowset1->m_pTable->CountColumnsOnTable(), m_pChgRowset1->m_rgTableColOrds, 1,
|
|
m_pResynchVisibleData, cBindings, rgBindings,
|
|
m_pChgRowset1->m_pTable, m_pIMalloc, PRIMARY,
|
|
FREE_ONLY
|
|
);
|
|
AllocDataBuffers(m_cbRowSize);
|
|
//free mem each time through the loop
|
|
FreeAccessorBindings(cBindings,rgBindings);
|
|
rgBindings = NULL;
|
|
if (hChgAccessor != DB_NULL_HACCESSOR)
|
|
{
|
|
m_pChgRowset1->m_pIAccessor->ReleaseAccessor(hChgAccessor, NULL);
|
|
}
|
|
if (hROAccessor != DB_NULL_HACCESSOR)
|
|
{
|
|
m_pRORowset1->m_pIAccessor->ReleaseAccessor(hROAccessor, NULL);
|
|
}
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
//If we broke before we finished loop, there was an error
|
|
if (i != STRESS_RESYNCH_REPS)
|
|
{
|
|
fResults = FALSE;
|
|
}
|
|
CLEANUP:
|
|
FreeOutParams();
|
|
if (fResults)
|
|
return TEST_PASS;
|
|
else
|
|
return TEST_FAIL;
|
|
}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(11)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc Own Update - Highest Isolation Level
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCPropCanHoldRowsResynchBLOBS::Variation_11()
|
|
{
|
|
BOOL fResults = FALSE;
|
|
HROW hRow = DB_NULL_HROW;
|
|
ULONG cRowsObtained = 0;
|
|
HRESULT hr;
|
|
BOOL fOverWrite = TRUE;
|
|
|
|
if (m_eTI==TI_IRowsetRefreshFALSE)
|
|
{
|
|
fOverWrite=FALSE;
|
|
}
|
|
|
|
//If no provider support for this isolation level, just return pass
|
|
if (!m_fChaos && !m_fReadUncommitted && !m_fReadCommitted &&
|
|
!m_fRepeatableRead && !m_fSerializable)
|
|
{
|
|
odtLog << wszNoProviderSupport << L"ANY" << wszNewLine;
|
|
return TEST_PASS;
|
|
}
|
|
|
|
//Not all drivers allow starting a txn with rowsets
|
|
//open, so release them before starting a txn
|
|
ReleaseResynchObjects();
|
|
|
|
//Set the highest possible isolation level, to make this test interesting
|
|
//since regardless of isolation, we should always see our own change.
|
|
//Note that we only start a txn for this rowset and not the RORowset,
|
|
//since otherwise the RORowset could lock us from changing
|
|
//due to the high isolation level
|
|
if (!CHECK(m_pChgRowset1->m_pITxnLocal->StartTransaction(m_fHighestSupportedIsoLevel, 0, NULL, NULL), S_OK))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
if (!COMPARE(CreateResynchObjects(m_eTI), TRUE))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
//Change a row ourselves and keep hRow
|
|
if (!COMPARE(m_pChgRowset1->Change(GetNextRowToDelete(), GetNextRowToInsert(), &hRow), TRUE))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
//increment for comparasion
|
|
g_ulLastActualInsert++;
|
|
|
|
//Next GetData from cache
|
|
if (!CHECK(m_pChgIRowset->GetData(hRow, m_hChgAccessor, m_pRowsetData), S_OK))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
//Now do a ResynchRows to see if new data is brought in
|
|
if (!CHECK(ResynchRefresh(DB_NULL_HCHAPTER,1, &hRow, fOverWrite, &m_cRowsResynched, &m_rghRowsResynched, &m_rgRowStatus, FALSE), S_OK))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
//Now Get Newly Resynch'd Data
|
|
if (!CHECK(m_pChgIRowset->GetData(hRow, m_hChgAccessor, m_pResynchRowsetData), S_OK))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
//Now GetVisibleData on the same row
|
|
hr=GetLastVisibleData(hRow, m_hChgAccessor, m_pResynchVisibleData,FALSE);
|
|
if (hr!=S_OK)
|
|
{
|
|
//account for the fact that some providers might delete/insert a row when asked to change it
|
|
//this may put a hole in the rowset and put the newrow somewhere else in the rowset (most likley at the end of the rowset)
|
|
if (DB_E_DELETEDROW==hr)
|
|
{
|
|
fResults = TRUE;
|
|
goto CLEANUP;
|
|
}
|
|
else
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
}
|
|
|
|
//no change is made, these should be the same
|
|
if(CompareBuffer(m_pResynchVisibleData,m_pResynchRowsetData,m_cBindings,m_rgBindings,m_pIMalloc,FALSE,FALSE,COMPARE_ONLY)!=TRUE)
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
|
|
//Now make sure we could see the new data at all times, since our own update
|
|
if (VerifyData(VERIFY_NEW, VERIFY_IGNORE, VERIFY_NEW, VERIFY_IGNORE))
|
|
{
|
|
//Everything went OK
|
|
fResults = TRUE;
|
|
}
|
|
CLEANUP:
|
|
FreeOutParams();
|
|
|
|
//bakc out changes
|
|
COMPARE(EndTxns(TRUE), TRUE);
|
|
g_ulLastActualInsert--;
|
|
|
|
if (hRow != DB_NULL_HROW)
|
|
m_pChgIRowset->ReleaseRows(1, &hRow, NULL, NULL, NULL);
|
|
|
|
if (fResults)
|
|
return TEST_PASS;
|
|
else
|
|
return TEST_FAIL;
|
|
}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(12)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc GetVisibleData with PASSBYREF - DB_E_BADACCESSORHANDLE
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCPropCanHoldRowsResynchBLOBS::Variation_12()
|
|
{
|
|
HACCESSOR hChgAccessor = DB_NULL_HACCESSOR;
|
|
BOOL fResults = FALSE;
|
|
HROW hRow = DB_NULL_HROW;
|
|
|
|
ReleaseResynchObjects();
|
|
if (!COMPARE(CreateResynchObjects(m_eTI), TRUE))
|
|
{
|
|
return FALSE;
|
|
}
|
|
//We will skip this variation is provider doesn't support PASSBYREF
|
|
if (!m_fPassByRef)
|
|
{
|
|
odtLog << L"This Provider doesn't support PASSBYREF accessors. Variation is not applicable.\n";
|
|
return TEST_PASS;
|
|
}
|
|
|
|
//Get a PASSBYREF accessor
|
|
if (CHECK(m_pChgRowset1->m_pIAccessor->CreateAccessor(
|
|
DBACCESSOR_ROWDATA | DBACCESSOR_PASSBYREF, m_cBindings,
|
|
m_rgBindings, m_cbRowSize, &hChgAccessor, NULL), S_OK))
|
|
{
|
|
//Get an hRow
|
|
if (COMPARE(m_pChgRowset1->FindRow(GetNextRowToDelete(), &hRow), TRUE))
|
|
{
|
|
//Any pass by ref accessor should fail
|
|
if (CHECK(GetLastVisibleData(hRow, hChgAccessor, m_pVisibleData, FALSE), DB_E_BADACCESSORHANDLE))
|
|
fResults = TRUE;
|
|
//Now clean up our row handle
|
|
m_pChgIRowset->ReleaseRows(1, &hRow, NULL, NULL, NULL);
|
|
}
|
|
m_pChgRowset1->m_pIAccessor->ReleaseAccessor(hChgAccessor, NULL);
|
|
}
|
|
|
|
if (fResults)
|
|
return TEST_PASS;
|
|
else
|
|
return TEST_FAIL;
|
|
}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(13)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc GetVisibleData with PROVIDEROWNED - DB_E_BADACCESSORHANDLE
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCPropCanHoldRowsResynchBLOBS::Variation_13()
|
|
{
|
|
HACCESSOR hChgAccessor = DB_NULL_HACCESSOR;
|
|
BOOL fResults = FALSE;
|
|
HROW hRow = DB_NULL_HROW;
|
|
DBBINDING *rgBindings = NULL;
|
|
DBCOUNTITEM cBindings = 0;
|
|
DBLENGTH cbRowSize = 0;
|
|
DBCOLUMNINFO *rgColInfo = NULL;
|
|
DBORDINAL cCols = 0;
|
|
ULONG i = 0;
|
|
ULONG j = 0;
|
|
OLECHAR *pStringsBuffer = NULL;
|
|
IColumnsInfo *pIColInfo = NULL;
|
|
BOOL fFoundNonLongCol= FALSE;
|
|
|
|
ReleaseResynchObjects();
|
|
if (!COMPARE(CreateResynchObjects(m_eTI), TRUE))
|
|
{
|
|
return FALSE;
|
|
}
|
|
//Get bindings for a by ref accessor, use variable len only cols
|
|
if (CHECK(GetAccessorAndBindings(m_pChgRowset1->m_pIAccessor, DBACCESSOR_ROWDATA,
|
|
&hChgAccessor, &rgBindings, &cBindings, &cbRowSize,
|
|
DBPART_VALUE | DBPART_LENGTH | DBPART_STATUS,
|
|
VARIABLE_LEN_COLS_BOUND, FORWARD, ALL_COLS_BY_REF,
|
|
NULL, NULL,
|
|
NULL, DBTYPE_EMPTY, 0, NULL, NULL,
|
|
NO_COLS_OWNED_BY_PROV, DBPARAMIO_NOTPARAM,
|
|
m_fBindLongData),S_OK))
|
|
{
|
|
//We only wanted bindings
|
|
CHECK(m_pChgRowset1->m_pIAccessor->ReleaseAccessor(hChgAccessor, NULL), S_OK);
|
|
hChgAccessor = DB_NULL_HACCESSOR;
|
|
|
|
//Get the col info
|
|
if (!VerifyInterface(m_pChgRowset1->m_pIAccessor, IID_IColumnsInfo, ROWSET_INTERFACE,(IUnknown **) &pIColInfo))
|
|
goto CLEANUP;
|
|
|
|
if (!CHECK(pIColInfo->GetColumnInfo(&cCols,
|
|
&rgColInfo, &pStringsBuffer), S_OK))
|
|
goto CLEANUP;
|
|
|
|
//Make sure we use a non blob column; they are not allowed
|
|
//for provider owned memory.
|
|
for (i=0; i<cBindings; i++)
|
|
{
|
|
//Loop thru the colinfo...
|
|
for (j=0; j<cCols; j++)
|
|
{
|
|
//...looking for the one which matches this binding
|
|
if (rgBindings[i].iOrdinal == rgColInfo[j].iOrdinal)
|
|
{
|
|
//Find one that doesn't have LONG DATA
|
|
if (!(rgColInfo[j].dwFlags & DBCOLUMNFLAGS_ISLONG))
|
|
{
|
|
rgBindings[i].dwMemOwner = DBMEMOWNER_PROVIDEROWNED;
|
|
|
|
//Mark that we found at least one non long col
|
|
fFoundNonLongCol = TRUE;
|
|
}
|
|
//We found our colinfo for this binding, so stop looking
|
|
break;
|
|
}
|
|
//We only need one binding with provider owned memory
|
|
if (fFoundNonLongCol)
|
|
break;
|
|
}
|
|
if (fFoundNonLongCol)
|
|
break;
|
|
}
|
|
|
|
//We couldn't find a non long column to make provider owned
|
|
if (!fFoundNonLongCol)
|
|
{
|
|
fResults = TRUE; //We can't test anything in this var
|
|
goto CLEANUP;
|
|
}
|
|
|
|
//Now create the accessor which has provider owned memory
|
|
if (CHECK(m_pChgRowset1->m_pIAccessor->CreateAccessor(DBACCESSOR_ROWDATA, cBindings,
|
|
rgBindings, cbRowSize, &hChgAccessor, NULL), S_OK))
|
|
{
|
|
//Get an hRow
|
|
if (COMPARE(m_pChgRowset1->FindRow(GetNextRowToDelete(), &hRow), TRUE))
|
|
{
|
|
//Now try with the provider owned memory binding to GetVisibleData
|
|
//This will either succeed or return an error if not supported
|
|
m_hr = GetLastVisibleData(hRow, hChgAccessor, m_pVisibleData, FALSE);
|
|
if (m_hr != S_OK)
|
|
CHECK(m_hr, DB_E_BADACCESSORHANDLE);
|
|
|
|
fResults = TRUE;
|
|
|
|
//Now clean up our row handle
|
|
m_pChgIRowset->ReleaseRows(1, &hRow, NULL, NULL, NULL);
|
|
}
|
|
m_pChgRowset1->m_pIAccessor->ReleaseAccessor(hChgAccessor, NULL);
|
|
}
|
|
}
|
|
CLEANUP:
|
|
if (rgBindings)
|
|
{
|
|
PROVIDER_FREE(rgBindings);
|
|
rgBindings = NULL;
|
|
}
|
|
|
|
if (rgColInfo)
|
|
{
|
|
PROVIDER_FREE(rgColInfo);
|
|
rgColInfo = NULL;
|
|
}
|
|
|
|
if (pIColInfo)
|
|
{
|
|
pIColInfo->Release();
|
|
pIColInfo = NULL;
|
|
}
|
|
|
|
if (pStringsBuffer)
|
|
{
|
|
PROVIDER_FREE(pStringsBuffer);
|
|
pStringsBuffer = NULL;
|
|
}
|
|
|
|
if (fResults)
|
|
return TEST_PASS;
|
|
else
|
|
return TEST_FAIL;
|
|
|
|
}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(14)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc ResynchRows/RefreshVisibleData with hRow = DB_NULL_HROW - DB_E_BADROWHANDLE
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCPropCanHoldRowsResynchBLOBS::Variation_14()
|
|
{
|
|
HROW hRow = DB_NULL_HROW;
|
|
BOOL fOverWrite = TRUE;
|
|
|
|
if (m_eTI==TI_IRowsetRefreshFALSE)
|
|
{
|
|
fOverWrite=FALSE;
|
|
}
|
|
|
|
ReleaseResynchObjects();
|
|
if (!COMPARE(CreateResynchObjects(m_eTI), TRUE))
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
m_cRowsResynched = 5;
|
|
m_rghRowsResynched = (HROW *)JUNK_PTR;
|
|
m_rgRowStatus = (DBROWSTATUS *)JUNK_PTR;
|
|
|
|
if (CHECK(ResynchRefresh(DB_NULL_HCHAPTER,1, &hRow, fOverWrite, &m_cRowsResynched,&m_rghRowsResynched, &m_rgRowStatus, FALSE), DB_E_ERRORSOCCURRED))
|
|
{
|
|
COMPARE(m_rghRowsResynched[0],DB_NULL_HROW);
|
|
COMPARE(m_cRowsResynched,1);
|
|
//Increment error count as needed while checking out param values
|
|
CompareOutParams(1, &hRow);
|
|
COMPARE(m_rgRowStatus[0], DBROWSTATUS_E_INVALID);
|
|
FreeOutParams();
|
|
|
|
//Note, provider not required to check for this return code
|
|
if (CHECK(GetLastVisibleData(hRow, m_hChgAccessor, m_pVisibleData, FALSE), DB_E_BADROWHANDLE))
|
|
{
|
|
return TEST_PASS;
|
|
}
|
|
}
|
|
FreeOutParams();
|
|
return TEST_FAIL;
|
|
}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(15)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc IRowsetResynch with hRow = hard deleted - DB_E_DELETEDROW
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCPropCanHoldRowsResynchBLOBS::Variation_15()
|
|
{
|
|
BOOL fResults = FALSE;
|
|
HROW hRow = DB_NULL_HROW;
|
|
BOOL fOverWrite = TRUE;
|
|
|
|
if (m_eTI==TI_IRowsetRefreshFALSE)
|
|
{
|
|
fOverWrite=FALSE;
|
|
}
|
|
ReleaseResynchObjects();
|
|
if (!COMPARE(CreateResynchObjects(m_eTI), TRUE))
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
//Delete the row with this txn
|
|
if (COMPARE(Delete(m_pChgRowset1, &hRow), TRUE))
|
|
{
|
|
m_cRowsResynched = 5;
|
|
m_rghRowsResynched = (HROW *)JUNK_PTR;
|
|
m_rgRowStatus = (DBROWSTATUS *)JUNK_PTR;
|
|
|
|
//Check that row status is deleted
|
|
if (CHECK(ResynchRefresh(DB_NULL_HCHAPTER,1, &hRow, fOverWrite, &m_cRowsResynched,&m_rghRowsResynched, &m_rgRowStatus, FALSE), DB_E_ERRORSOCCURRED))
|
|
{
|
|
COMPARE(m_rghRowsResynched[0],hRow);
|
|
COMPARE(m_cRowsResynched,1);
|
|
CompareOutParams(1, &hRow);
|
|
|
|
if (COMPARE(m_rgRowStatus[0], DBROWSTATUS_E_DELETED))
|
|
{
|
|
//if there is no visual cache GetLastVisibleData has
|
|
//to go to the back end.
|
|
//if there is a visual cache GetLastVisibleData sees the delete anyway
|
|
//because it was a hard delete
|
|
if (CHECK(GetLastVisibleData(hRow, m_hChgAccessor, m_pResynchVisibleData,FALSE), DB_E_DELETEDROW))
|
|
{
|
|
fResults = TRUE;
|
|
}
|
|
}
|
|
FreeOutParams();
|
|
}
|
|
}
|
|
//Release the row
|
|
if (hRow != DB_NULL_HROW)
|
|
{
|
|
m_pChgIRowset->ReleaseRows(1, &hRow, NULL, NULL, NULL);
|
|
}
|
|
//We want to release our rowset so the deleted hRow we introduced
|
|
//won't be around for subsequent calls to GetNextRows (which should
|
|
//cause Resynch methods to fail with DELETED ROW)
|
|
ReleaseResynchObjects();
|
|
//Set up for next variation
|
|
COMPARE(CreateResynchObjects(m_eTI), TRUE);
|
|
|
|
if (fResults)
|
|
return TEST_PASS;
|
|
else
|
|
return TEST_FAIL;
|
|
}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(16)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc ResynchRows/RefreshVisibleData with hRow = row deleted by another txn - DB_E_DELETEDROW
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCPropCanHoldRowsResynchBLOBS::Variation_16()
|
|
{
|
|
HROW hRow = DB_NULL_HROW;
|
|
BOOL fResults = FALSE;
|
|
BOOL fOverWrite = TRUE;
|
|
HRESULT hr;
|
|
ULONG i = 0;
|
|
|
|
|
|
if (m_eTI==TI_IRowsetRefreshFALSE)
|
|
{
|
|
fOverWrite=FALSE;
|
|
}
|
|
|
|
ReleaseResynchObjects();
|
|
if (!COMPARE(CreateResynchObjects(m_eTI), TRUE))
|
|
{
|
|
return FALSE;
|
|
}
|
|
//Get row so that provider has it in cache before we change it from another txn
|
|
if (COMPARE(m_pChgRowset1->FindRow(GetNextRowToDelete(), &hRow), TRUE))
|
|
{
|
|
//Delete the row using another txn
|
|
if (COMPARE(Delete(m_pChgRowset2), TRUE))
|
|
{
|
|
if (m_fOnAccess)
|
|
Sleep(SLEEP_TIME); //Takes milliseconds as param
|
|
|
|
m_cRowsResynched = 5;
|
|
m_rghRowsResynched = (HROW *)JUNK_PTR;
|
|
m_rgRowStatus = (DBROWSTATUS *)JUNK_PTR;
|
|
if (CHECK(ResynchRefresh(DB_NULL_HCHAPTER,1, &hRow, fOverWrite, &m_cRowsResynched,&m_rghRowsResynched, &m_rgRowStatus, FALSE), DB_E_ERRORSOCCURRED))
|
|
{
|
|
COMPARE(m_rghRowsResynched[0],hRow);
|
|
COMPARE(m_cRowsResynched,1);
|
|
CompareOutParams(1, &hRow);
|
|
|
|
if (COMPARE(m_rgRowStatus[0], DBROWSTATUS_E_DELETED))
|
|
{
|
|
//if there is no visual cache GetLastVisibleData has
|
|
//to go to the back end.
|
|
if (m_eTI==TI_IRowsetResynch || !g_fVisualCache)
|
|
{
|
|
if (CHECK(GetLastVisibleData(hRow, m_hChgAccessor, m_pResynchVisibleData,FALSE), DB_E_DELETEDROW))
|
|
{
|
|
fResults = TRUE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//if this is Refresh and there is a visual cache
|
|
//GetLastVisibleData will succeed. RefreshVisibleData failed,
|
|
//no row was refreshed. GetLastVisibleData gets the current
|
|
//visual cache row value
|
|
if (g_fVisualCache)
|
|
{
|
|
hr = GetLastVisibleData(hRow, m_hChgAccessor, m_pResynchVisibleData,FALSE);
|
|
|
|
if (DB_S_ERRORSOCCURRED==hr)
|
|
{
|
|
for (i=0;i<m_cBindings;i++)
|
|
{
|
|
//if there is a BLOB it will be UNAVAILABLE so allow for it as
|
|
//a valid status for DB_S_ERRORSOCCURRED
|
|
if (
|
|
*((BYTE *)m_pResynchVisibleData+(m_rgBindings[i]).obStatus)==DBSTATUS_E_UNAVAILABLE
|
|
)
|
|
{
|
|
fResults = TRUE;
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
if (S_OK==hr)
|
|
{
|
|
fResults = TRUE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
FreeOutParams();
|
|
}
|
|
}
|
|
//Release the row
|
|
if (hRow != DB_NULL_HROW)
|
|
{
|
|
m_pChgIRowset->ReleaseRows(1, &hRow, NULL, NULL, NULL);
|
|
}
|
|
//We want to release our rowset so the deleted hRow we introduced
|
|
//won't be around for subsequent calls to GetNextRows (which should
|
|
//cause Resynch methods to fail with DELETED ROW)
|
|
ReleaseResynchObjects();
|
|
//Set up for next variation
|
|
COMPARE(CreateResynchObjects(m_eTI), TRUE);
|
|
|
|
if (fResults)
|
|
return TEST_PASS;
|
|
else
|
|
return TEST_FAIL;
|
|
}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(17)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc GetVisibleData with pData = NULL - E_INVALIDARG
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCPropCanHoldRowsResynchBLOBS::Variation_17()
|
|
{
|
|
BOOL fResults = FALSE;
|
|
HROW hRow = DB_NULL_HROW;
|
|
|
|
ReleaseResynchObjects();
|
|
if (!COMPARE(CreateResynchObjects(m_eTI), TRUE))
|
|
{
|
|
return FALSE;
|
|
}
|
|
//Get valid hRow
|
|
if (COMPARE(m_pChgRowset1->FindRow(GetNextRowToDelete(), &hRow), TRUE))
|
|
{
|
|
//Try all valid params except pData = NULL
|
|
if (CHECK(GetLastVisibleData(hRow, m_hChgAccessor, NULL, FALSE), E_INVALIDARG))
|
|
fResults = TRUE;
|
|
|
|
m_pChgIRowset->ReleaseRows(1, &hRow, NULL, NULL, NULL);
|
|
}
|
|
|
|
|
|
if (fResults)
|
|
return TEST_PASS;
|
|
else
|
|
return TEST_FAIL;
|
|
}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(18)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc GetVisibleData with Null Accessor, pData = NULL
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCPropCanHoldRowsResynchBLOBS::Variation_18()
|
|
{
|
|
HROW hRow = DB_NULL_HROW;
|
|
HACCESSOR hChgAccessor = DB_NULL_HACCESSOR;
|
|
BOOL fResults = FALSE;
|
|
HRESULT hr;
|
|
BOOL fOverWrite = TRUE;
|
|
|
|
if (m_eTI==TI_IRowsetRefreshFALSE)
|
|
{
|
|
fOverWrite=FALSE;
|
|
}
|
|
|
|
ReleaseResynchObjects();
|
|
if (!COMPARE(CreateResynchObjects(m_eTI), TRUE))
|
|
{
|
|
return FALSE;
|
|
}
|
|
if (CHECK(m_pChgRowset1->m_pIAccessor->CreateAccessor(DBACCESSOR_ROWDATA,0, NULL, 0, &hChgAccessor, NULL), S_OK))
|
|
{
|
|
if (ChangeUnderlyingRowAndGetHrow(m_pChgRowset1, ISOLATIONLEVEL_CHAOS, &hRow))
|
|
{
|
|
/////////////////////////////////////////////////////////////////////
|
|
//Use null accessor and NULL pData, so all these should get no data
|
|
/////////////////////////////////////////////////////////////////////
|
|
|
|
//Get data which should already be in the cache
|
|
if (CHECK(m_pChgIRowset->GetData(hRow, hChgAccessor, NULL), S_OK))
|
|
{ //Resynch the cache
|
|
hr=ResynchRefresh(DB_NULL_HCHAPTER,1,&hRow, fOverWrite, &m_cRowsResynched,&m_rghRowsResynched,&m_rgRowStatus, FALSE);
|
|
if (!hr==S_OK)
|
|
{
|
|
//account for the fact that some providers might delete/insert a row when asked to change it
|
|
//this may put a hole in the rowset and put the newrow somewhere else in the rowset (most likley at the end of the rowset)
|
|
if (DB_S_ERRORSOCCURRED==hr || DB_E_ERRORSOCCURRED==hr)
|
|
{
|
|
COMPARE(1,m_cRowsResynched);
|
|
if (COMPARE(m_rgRowStatus[0],DBROWSTATUS_E_DELETED))
|
|
{
|
|
fResults = TRUE;
|
|
}
|
|
}
|
|
goto CLEANUP;
|
|
}
|
|
else
|
|
{
|
|
CompareOutParams(1, &hRow);
|
|
if (g_fNOCHANGE)
|
|
{
|
|
//no change was made here, if the provider can handle it, expect it
|
|
COMPARE(m_rgRowStatus[0], DBROWSTATUS_S_NOCHANGE);
|
|
}
|
|
else
|
|
{
|
|
COMPARE(m_rgRowStatus[0], DBROWSTATUS_S_OK);
|
|
}
|
|
|
|
//Try to get new visible data
|
|
if (CHECK(GetLastVisibleData(hRow, hChgAccessor,NULL, FALSE), S_OK))
|
|
{
|
|
//Now try to get Newly Resynch'd Data
|
|
if (CHECK(m_pChgIRowset->GetData(hRow, hChgAccessor, NULL), S_OK))
|
|
{
|
|
fResults = TRUE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
CLEANUP:
|
|
FreeOutParams();
|
|
if (hRow != DB_NULL_HROW)
|
|
m_pChgIRowset->ReleaseRows(1, &hRow, NULL, NULL, NULL);
|
|
|
|
if (hChgAccessor != DB_NULL_HACCESSOR)
|
|
if (CHECK(m_pChgRowset1->m_pIAccessor->ReleaseAccessor(hChgAccessor, NULL), S_OK))
|
|
hChgAccessor = DB_NULL_HACCESSOR;
|
|
if (fResults)
|
|
return TEST_PASS;
|
|
else
|
|
return TEST_FAIL;
|
|
}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(19)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc GetVisibleData with Null Accessor, pData valid
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCPropCanHoldRowsResynchBLOBS::Variation_19()
|
|
{
|
|
HROW hRow = DB_NULL_HROW;
|
|
HACCESSOR hChgAccessor = DB_NULL_HACCESSOR;
|
|
BYTE *pCompareData = NULL;
|
|
BOOL fResults = FALSE;
|
|
HRESULT hr;
|
|
BOOL fOverWrite = TRUE;
|
|
|
|
if (m_eTI==TI_IRowsetRefreshFALSE)
|
|
{
|
|
fOverWrite=FALSE;
|
|
}
|
|
|
|
ReleaseResynchObjects();
|
|
if (!COMPARE(CreateResynchObjects(m_eTI), TRUE))
|
|
{
|
|
return FALSE;
|
|
}
|
|
pCompareData = (BYTE *)PROVIDER_ALLOC(m_cbRowSize);
|
|
if (!pCompareData)
|
|
{
|
|
return TEST_FAIL;
|
|
}
|
|
memset(pCompareData,0,(size_t)m_cbRowSize);
|
|
|
|
//Set buffers so we know if they've been touched
|
|
memset(m_pRowsetData, 0, (size_t)m_cbRowSize);
|
|
memset(m_pVisibleData, 0, (size_t)m_cbRowSize);
|
|
memset(m_pResynchRowsetData, 0, (size_t)m_cbRowSize);
|
|
memset(pCompareData, 0, (size_t)m_cbRowSize);
|
|
|
|
if (CHECK(m_pChgRowset1->m_pIAccessor->CreateAccessor(DBACCESSOR_ROWDATA,0, NULL, 0, &hChgAccessor, NULL), S_OK))
|
|
{
|
|
if (ChangeUnderlyingRowAndGetHrow(m_pChgRowset1, ISOLATIONLEVEL_CHAOS, &hRow))
|
|
{
|
|
/////////////////////////////////////////////////////
|
|
//Use null accessor, so all these should get no data
|
|
/////////////////////////////////////////////////////
|
|
|
|
//Get data which should already be in the cache
|
|
if (CHECK(m_pChgIRowset->GetData(hRow, hChgAccessor, m_pRowsetData), S_OK))
|
|
{
|
|
//Resynch the cache
|
|
hr=ResynchRefresh(DB_NULL_HCHAPTER,1,&hRow, fOverWrite, &m_cRowsResynched,&m_rghRowsResynched,&m_rgRowStatus, FALSE);
|
|
if (!hr==S_OK)
|
|
{
|
|
//account for the fact that some providers might delete/insert a row when asked to change it
|
|
//this may put a hole in the rowset and put the newrow somewhere else in the rowset (most likley at the end of the rowset)
|
|
if (DB_S_ERRORSOCCURRED==hr||DB_E_ERRORSOCCURRED==hr)
|
|
{
|
|
COMPARE(1,m_cRowsResynched);
|
|
if (COMPARE(m_rgRowStatus[0],DBROWSTATUS_E_DELETED))
|
|
{
|
|
fResults = TRUE;
|
|
}
|
|
}
|
|
goto CLEANUP;
|
|
}
|
|
else
|
|
{
|
|
if (g_fNOCHANGE)
|
|
{
|
|
//no change was made here, if the provider can handle it, expect it
|
|
COMPARE(m_rgRowStatus[0], DBROWSTATUS_S_NOCHANGE);
|
|
}
|
|
else
|
|
{
|
|
COMPARE(m_rgRowStatus[0], DBROWSTATUS_S_OK);
|
|
}
|
|
|
|
FreeOutParams();
|
|
|
|
//Try to get new visible data
|
|
if (CHECK(GetLastVisibleData(hRow, hChgAccessor,m_pResynchVisibleData, FALSE), S_OK))
|
|
{
|
|
//Now try to get Newly Resynch'd Data
|
|
if (CHECK(m_pChgIRowset->GetData(hRow, hChgAccessor, m_pResynchRowsetData), S_OK))
|
|
{
|
|
//No of the buffers should have been touched, 0 == identical
|
|
if (COMPARE(CompareBuffer(m_pRowsetData,pCompareData,m_cBindings,m_rgBindings,m_pIMalloc,FALSE,FALSE,COMPARE_ONLY),TRUE) &&
|
|
COMPARE(CompareBuffer(m_pResynchVisibleData,pCompareData,m_cBindings,m_rgBindings,m_pIMalloc,FALSE,FALSE,COMPARE_ONLY),TRUE) &&
|
|
COMPARE(CompareBuffer(m_pResynchRowsetData,pCompareData,m_cBindings,m_rgBindings,m_pIMalloc,FALSE,FALSE,COMPARE_ONLY),TRUE))
|
|
{
|
|
fResults = TRUE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
CLEANUP:
|
|
FreeOutParams();
|
|
PROVIDER_FREE(pCompareData);
|
|
|
|
if (hRow != DB_NULL_HROW)
|
|
m_pChgIRowset->ReleaseRows(1, &hRow, NULL, NULL, NULL);
|
|
|
|
if (hChgAccessor != DB_NULL_HACCESSOR)
|
|
CHECK(m_pChgRowset1->m_pIAccessor->ReleaseAccessor(hChgAccessor, NULL), S_OK);
|
|
if (fResults)
|
|
return TEST_PASS;
|
|
else
|
|
return TEST_FAIL;
|
|
}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(20)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc Fetch Position
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCPropCanHoldRowsResynchBLOBS::Variation_20()
|
|
{
|
|
ReleaseResynchObjects();
|
|
if (!COMPARE(CreateResynchObjects(m_eTI), TRUE))
|
|
{
|
|
return FALSE;
|
|
}
|
|
return TestFetchPosition(m_pChgIRowset, m_pChgIRowsetResynch, m_pChgIRowsetRefresh);
|
|
|
|
}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(21)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc Rows 1 and n
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCPropCanHoldRowsResynchBLOBS::Variation_21()
|
|
{
|
|
ReleaseResynchObjects();
|
|
if (!COMPARE(CreateResynchObjects(m_eTI), TRUE))
|
|
{
|
|
return FALSE;
|
|
}
|
|
return TestRows1AndN(m_pChgIRowset, m_pChgIRowsetResynch, m_pChgIRowsetRefresh);
|
|
}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(22)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc All Rows
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCPropCanHoldRowsResynchBLOBS::Variation_22()
|
|
{
|
|
ReleaseResynchObjects();
|
|
if (!COMPARE(CreateResynchObjects(m_eTI), TRUE))
|
|
{
|
|
return FALSE;
|
|
}
|
|
return TestAllRows(m_pChgIRowset, m_pChgIRowsetResynch, m_pChgIRowsetRefresh);
|
|
}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(23)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc ResynchRows with rghRows = NULL - E_INVALIDARG
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCPropCanHoldRowsResynchBLOBS::Variation_23()
|
|
{
|
|
BOOL fOverWrite = TRUE;
|
|
|
|
if (m_eTI==TI_IRowsetRefreshFALSE)
|
|
{
|
|
fOverWrite=FALSE;
|
|
}
|
|
|
|
ReleaseResynchObjects();
|
|
if (!COMPARE(CreateResynchObjects(m_eTI), TRUE))
|
|
{
|
|
return FALSE;
|
|
}
|
|
//All valid args except rghRows
|
|
if (CHECK(ResynchRefresh(DB_NULL_HCHAPTER,1, NULL, fOverWrite, &m_cRowsResynched, &m_rghRowsResynched, &m_rgRowStatus, FALSE), E_INVALIDARG))
|
|
{
|
|
//Make sure all out parameters are zeroed/nulled out on error
|
|
CheckOutParamsAreNulled();
|
|
FreeOutParams();
|
|
return TEST_PASS;
|
|
}
|
|
else
|
|
{
|
|
FreeOutParams();
|
|
return TEST_FAIL;
|
|
}
|
|
}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(24)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc ResynchRows with one invalid hRow - DBROWSTATUS_E_INVALID
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCPropCanHoldRowsResynchBLOBS::Variation_24()
|
|
{
|
|
HROW *phRows = NULL;
|
|
BOOL fResults = FALSE;
|
|
HROW hSaveRow = DB_NULL_HROW;
|
|
DBCOUNTITEM cRowsObtained = 0;
|
|
ULONG i = 0;
|
|
BOOL fOverWrite = TRUE;
|
|
|
|
if (m_eTI==TI_IRowsetRefreshFALSE)
|
|
{
|
|
fOverWrite=FALSE;
|
|
}
|
|
|
|
ReleaseResynchObjects();
|
|
if (!COMPARE(CreateResynchObjects(m_eTI), TRUE))
|
|
{
|
|
return FALSE;
|
|
}
|
|
//Make sure we are at beginning of rowset after other variations
|
|
CHECK(m_pChgIRowset->RestartPosition(NULL), S_OK);
|
|
|
|
//Get all the rows, ask for more than enough
|
|
if (CHECK(m_pChgIRowset->GetNextRows(NULL, 0, NUM_ROWS * 3, &cRowsObtained, &phRows), DB_S_ENDOFROWSET))
|
|
{
|
|
//Now make one of the elements invalid
|
|
hSaveRow = phRows[cRowsObtained/2];
|
|
phRows[cRowsObtained/2] = DB_NULL_HROW;
|
|
|
|
//Resynch all the rows
|
|
if (CHECK(ResynchRefresh(DB_NULL_HCHAPTER,cRowsObtained, phRows, fOverWrite, &m_cRowsResynched, &m_rghRowsResynched, &m_rgRowStatus, FALSE), DB_S_ERRORSOCCURRED))
|
|
{
|
|
CompareOutParams(cRowsObtained, phRows);
|
|
|
|
//Verify status is correct for each element
|
|
for (i=0; i<cRowsObtained; i++)
|
|
{
|
|
if (i == cRowsObtained /2)
|
|
COMPARE(m_rgRowStatus[i], DBROWSTATUS_E_INVALID);
|
|
else
|
|
{
|
|
if (g_fNOCHANGE)
|
|
{
|
|
//no change was made here, if the provider can handle it, expect it
|
|
COMPARE(m_rgRowStatus[i], DBROWSTATUS_S_NOCHANGE);
|
|
}
|
|
else
|
|
{
|
|
COMPARE(m_rgRowStatus[i], DBROWSTATUS_S_OK);
|
|
}
|
|
}
|
|
}
|
|
|
|
fResults = TRUE;
|
|
}
|
|
|
|
|
|
//Move our munged row back so we can free whole array
|
|
phRows[cRowsObtained/2] = hSaveRow;
|
|
|
|
CHECK(m_pChgIRowset->ReleaseRows(cRowsObtained, phRows, NULL, NULL, NULL), S_OK);
|
|
|
|
if (phRows)
|
|
{
|
|
PROVIDER_FREE(phRows);
|
|
}
|
|
}
|
|
FreeOutParams();
|
|
if (fResults)
|
|
return TEST_PASS;
|
|
else
|
|
return TEST_FAIL;
|
|
}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(25)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc ResynchRows with all invalid hRows - DBROWSTATUS_E_INVALID
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCPropCanHoldRowsResynchBLOBS::Variation_25()
|
|
{
|
|
HROW rgRows[(NUM_ROWS*2)];
|
|
ULONG i;
|
|
BOOL fOverWrite = TRUE;
|
|
|
|
if (m_eTI==TI_IRowsetRefreshFALSE)
|
|
{
|
|
fOverWrite=FALSE;
|
|
}
|
|
|
|
ReleaseResynchObjects();
|
|
if (!COMPARE(CreateResynchObjects(m_eTI), TRUE))
|
|
{
|
|
return FALSE;
|
|
}
|
|
//Make all hRows invalid
|
|
for (i=0; i< (NUM_ROWS*2); i++)
|
|
rgRows[i] = DB_NULL_HROW;
|
|
|
|
m_cRowsResynched = 5;
|
|
m_rghRowsResynched = (HROW *)JUNK_PTR;
|
|
m_rgRowStatus = (DBROWSTATUS *)JUNK_PTR;
|
|
//Try to Resynch all the invalid rows
|
|
if (CHECK(ResynchRefresh(DB_NULL_HCHAPTER,(NUM_ROWS*2), rgRows, fOverWrite, &m_cRowsResynched, &m_rghRowsResynched, &m_rgRowStatus, FALSE), DB_E_ERRORSOCCURRED))
|
|
{
|
|
for (i=0; i< (NUM_ROWS*2); i++)
|
|
{
|
|
COMPARE(m_rghRowsResynched[i],DB_NULL_HROW);
|
|
}
|
|
COMPARE(m_cRowsResynched,(NUM_ROWS*2));
|
|
CompareOutParams((NUM_ROWS*2), rgRows);
|
|
|
|
for (i=0; i<(NUM_ROWS*2); i++)
|
|
{
|
|
COMPARE(m_rgRowStatus[i], DBROWSTATUS_E_INVALID);
|
|
}
|
|
FreeOutParams();
|
|
|
|
return TEST_PASS;
|
|
}
|
|
FreeOutParams();
|
|
return TEST_FAIL;
|
|
}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(26)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc ResynchRows with cRows = 0 and no active hRows
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCPropCanHoldRowsResynchBLOBS::Variation_26()
|
|
{
|
|
HROW *pJunkHRow = (HROW *)JUNK_PTR;
|
|
BOOL fOverWrite = TRUE;
|
|
|
|
if (m_eTI==TI_IRowsetRefreshFALSE)
|
|
{
|
|
fOverWrite=FALSE;
|
|
}
|
|
|
|
ReleaseResynchObjects();
|
|
if (!COMPARE(CreateResynchObjects(m_eTI), TRUE))
|
|
{
|
|
return FALSE;
|
|
}
|
|
//Make sure pJunkHrow is ignored with cRows is 0
|
|
if (CHECK(ResynchRefresh(DB_NULL_HCHAPTER,0, pJunkHRow, fOverWrite, &m_cRowsResynched, &m_rghRowsResynched, &m_rgRowStatus, FALSE), S_OK))
|
|
{
|
|
//The three output params should be nulled/zeroed out
|
|
CheckOutParamsAreNulled();
|
|
FreeOutParams();
|
|
return TEST_PASS;
|
|
}
|
|
FreeOutParams();
|
|
return TEST_FAIL;
|
|
}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(27)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc ResynchRows/RefreshVisibleData with held hRows from different GetNextRows calls, cRows=0
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCPropCanHoldRowsResynchBLOBS::Variation_27()
|
|
{
|
|
HROW rghRow[2];
|
|
HROW *phRows1 = &rghRow[0];
|
|
HROW *phRows2 = &rghRow[1];
|
|
BOOL fResults = FALSE;
|
|
DBCOUNTITEM cRowsObtained = 0;
|
|
BOOL fOverWrite = TRUE;
|
|
|
|
if (m_eTI==TI_IRowsetRefreshFALSE)
|
|
{
|
|
fOverWrite=FALSE;
|
|
}
|
|
|
|
ReleaseResynchObjects();
|
|
if (!COMPARE(CreateResynchObjects(m_eTI), TRUE))
|
|
{
|
|
return FALSE;
|
|
}
|
|
//Make sure we are at beginning of rowset after other variations
|
|
CHECK(m_pChgIRowset->RestartPosition(NULL), S_OK);
|
|
//Get one row
|
|
if (CHECK(m_pChgIRowset->GetNextRows(NULL, 0, 1, &cRowsObtained, &phRows1), S_OK))
|
|
{
|
|
//Get another row
|
|
if (CHECK(m_pChgIRowset->GetNextRows(NULL, 0, 1, &cRowsObtained, &phRows2), S_OK))
|
|
{
|
|
//Resynch all the rows from multiple GetNextRows calls
|
|
if (CHECK(ResynchRefresh(DB_NULL_HCHAPTER,0, NULL, fOverWrite, &m_cRowsResynched, &m_rghRowsResynched, &m_rgRowStatus, FALSE), S_OK))
|
|
{
|
|
//Even though we got the hRows in two calls,
|
|
//we put consecutively in one array
|
|
CompareOutParams(2, rghRow);
|
|
|
|
if (g_fNOCHANGE)
|
|
{
|
|
//no change was made here, if the provider can handle it, expect it
|
|
COMPARE(m_rgRowStatus[0], DBROWSTATUS_S_NOCHANGE);
|
|
COMPARE(m_rgRowStatus[1], DBROWSTATUS_S_NOCHANGE);
|
|
}
|
|
else
|
|
{
|
|
COMPARE(m_rgRowStatus[0], DBROWSTATUS_S_OK);
|
|
COMPARE(m_rgRowStatus[1], DBROWSTATUS_S_OK);
|
|
}
|
|
fResults = TRUE;
|
|
}
|
|
|
|
//Release second row
|
|
CHECK(m_pChgIRowset->ReleaseRows(1, phRows2, NULL, NULL, NULL), S_OK);
|
|
}
|
|
|
|
//Release first row
|
|
CHECK(m_pChgIRowset->ReleaseRows(1, phRows1, NULL, NULL, NULL), S_OK);
|
|
}
|
|
FreeOutParams();
|
|
if (fResults)
|
|
return TEST_PASS;
|
|
else
|
|
return TEST_FAIL;
|
|
}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(28)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc ResynchRows/RefreshVisibleData with held hRows from different GetNextRows calls, cRows exact
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCPropCanHoldRowsResynchBLOBS::Variation_28()
|
|
{
|
|
HROW rghRow[2];
|
|
HROW *phRows1 = &rghRow[0];
|
|
HROW *phRows2 = &rghRow[1];
|
|
BOOL fResults = FALSE;
|
|
DBCOUNTITEM cRowsObtained = 0;
|
|
BOOL fOverWrite = TRUE;
|
|
|
|
if (m_eTI==TI_IRowsetRefreshFALSE)
|
|
{
|
|
fOverWrite=FALSE;
|
|
}
|
|
|
|
ReleaseResynchObjects();
|
|
if (!COMPARE(CreateResynchObjects(m_eTI), TRUE))
|
|
{
|
|
return FALSE;
|
|
}
|
|
//Make sure we are at beginning of rowset after other variations
|
|
CHECK(m_pChgIRowset->RestartPosition(NULL), S_OK);
|
|
//Get one row
|
|
if (CHECK(m_pChgIRowset->GetNextRows(NULL, 0, 1, &cRowsObtained, &phRows1), S_OK))
|
|
{
|
|
//Get another row
|
|
if (CHECK(m_pChgIRowset->GetNextRows(NULL, 0, 1, &cRowsObtained, &phRows2), S_OK))
|
|
{
|
|
//Resynch all the rows from multiple GetNextRows calls, using
|
|
//exact hRows rather than cRows = 0
|
|
if (CHECK(ResynchRefresh(DB_NULL_HCHAPTER,2, rghRow, fOverWrite, &m_cRowsResynched, &m_rghRowsResynched, &m_rgRowStatus, FALSE), S_OK))
|
|
{
|
|
//Even though we got the hRows in two calls,
|
|
//we put consecutively in one array
|
|
CompareOutParams(2, rghRow);
|
|
if (g_fNOCHANGE)
|
|
{
|
|
//no change was made here, if the provider can handle it, expect it
|
|
COMPARE(m_rgRowStatus[0], DBROWSTATUS_S_NOCHANGE);
|
|
COMPARE(m_rgRowStatus[1], DBROWSTATUS_S_NOCHANGE);
|
|
}
|
|
else
|
|
{
|
|
COMPARE(m_rgRowStatus[0], DBROWSTATUS_S_OK);
|
|
COMPARE(m_rgRowStatus[1], DBROWSTATUS_S_OK);
|
|
}
|
|
fResults = TRUE;
|
|
}
|
|
|
|
//Release second row
|
|
CHECK(m_pChgIRowset->ReleaseRows(1, phRows2, NULL, NULL, NULL), S_OK);
|
|
|
|
}
|
|
|
|
//Release first row
|
|
CHECK(m_pChgIRowset->ReleaseRows(1, phRows1, NULL, NULL, NULL), S_OK);
|
|
}
|
|
FreeOutParams();
|
|
if (fResults)
|
|
return TEST_PASS;
|
|
else
|
|
return TEST_FAIL;
|
|
}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(29)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc Fetch Position with Read Only Rowset
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCPropCanHoldRowsResynchBLOBS::Variation_29()
|
|
{
|
|
ReleaseResynchObjects();
|
|
if (!COMPARE(CreateResynchObjects(m_eTI), TRUE))
|
|
{
|
|
return FALSE;
|
|
}
|
|
return TestFetchPosition(m_pROIRowset, m_pROIRowsetResynch, m_pROIRowsetRefresh);
|
|
}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(30)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc Rows 1 and n with Read Only Rowset
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCPropCanHoldRowsResynchBLOBS::Variation_30()
|
|
{
|
|
ReleaseResynchObjects();
|
|
if (!COMPARE(CreateResynchObjects(m_eTI), TRUE))
|
|
{
|
|
return FALSE;
|
|
}
|
|
return TestRows1AndN(m_pROIRowset, m_pROIRowsetResynch, m_pROIRowsetRefresh);
|
|
}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(31)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc All Rows with Read Only Rowset
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCPropCanHoldRowsResynchBLOBS::Variation_31()
|
|
{
|
|
ReleaseResynchObjects();
|
|
if (!COMPARE(CreateResynchObjects(m_eTI), TRUE))
|
|
{
|
|
return FALSE;
|
|
}
|
|
return TestAllRows(m_pROIRowset, m_pROIRowsetResynch, m_pROIRowsetRefresh);
|
|
}
|
|
// }}
|
|
// {{ TCW_TERMINATE_METHOD
|
|
//--------------------------------------------------------------------
|
|
// @mfunc TestCase Termination Routine
|
|
//
|
|
// @rdesc TRUE or FALSE
|
|
//
|
|
BOOL TCPropCanHoldRowsResynchBLOBS::Terminate()
|
|
{
|
|
// TO DO: Add your own code here
|
|
|
|
// {{ TCW_TERM_BASECLASS_CHECK2
|
|
return(CPropCanHoldRowsResynch::Terminate());
|
|
} // }}
|
|
// }}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_TC_PROTOTYPE(TCNullRowResynch)
|
|
//*-----------------------------------------------------------------------
|
|
//| Test Case: TCNullRowResynch - Tests Resych with all NULLs
|
|
//| Created: 10/14/96
|
|
//*-----------------------------------------------------------------------
|
|
|
|
//--------------------------------------------------------------------
|
|
// @mfunc TestCase Initialization Routine
|
|
//
|
|
// @rdesc TRUE or FALSE
|
|
//
|
|
BOOL TCNullRowResynch::Init()
|
|
{
|
|
const ULONG cProps = 3;
|
|
DBPROP rgNewDBProp[cProps];
|
|
DBPROPSET NewPropSet;
|
|
IRowsetChange *pIRowsetChange = NULL;
|
|
BOOL fResults = TEST_FAIL;
|
|
ULONG j = 0;
|
|
DBCOUNTITEM cRowsObtained = 0;
|
|
HRESULT hr;
|
|
|
|
|
|
m_pITransactionLocal = NULL;
|
|
m_rgBindings = NULL;
|
|
m_cBindings = 0;
|
|
m_cbRowSize = 0;
|
|
m_hAccessor = DB_NULL_HACCESSOR;
|
|
m_pIRowset = NULL;
|
|
m_phRow = &m_hRow;
|
|
m_hRow = DB_NULL_HROW;
|
|
m_pData = NULL;
|
|
|
|
if (TEST_SKIPPED==fnInterfaceSupported())
|
|
{
|
|
return TEST_SKIPPED;
|
|
}
|
|
|
|
// {{ TCW_INIT_BASECLASS_CHECK
|
|
if(CRowsetObject::Init())
|
|
// }}
|
|
{
|
|
//Get IRowset on the object
|
|
if (!VerifyInterface((IUnknown *)m_pThisTestModule->m_pIUnknown2,
|
|
IID_ITransactionLocal, SESSION_INTERFACE, (IUnknown **)&m_pITransactionLocal))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
m_pITransactionLocal->StartTransaction(ISOLATIONLEVEL_READCOMMITTED, 0, NULL, NULL);
|
|
|
|
//Set up our rowset properties
|
|
rgNewDBProp[0].dwPropertyID = DBPROP_UPDATABILITY;
|
|
rgNewDBProp[0].dwOptions = DBPROPOPTIONS_REQUIRED;
|
|
rgNewDBProp[0].colid = DB_NULLID;
|
|
rgNewDBProp[0].vValue.vt = VT_I4;
|
|
rgNewDBProp[0].vValue.lVal = DBPROPVAL_UP_INSERT | DBPROPVAL_UP_CHANGE | DBPROPVAL_UP_DELETE;
|
|
|
|
if (m_eTI==TI_IRowsetResynch)
|
|
{
|
|
rgNewDBProp[1].dwPropertyID = DBPROP_IRowsetResynch;
|
|
rgNewDBProp[1].dwOptions = DBPROPOPTIONS_REQUIRED;
|
|
rgNewDBProp[1].colid = DB_NULLID;
|
|
rgNewDBProp[1].vValue.vt = VT_BOOL;
|
|
V_BOOL(&(rgNewDBProp[1].vValue)) = VARIANT_TRUE;
|
|
}
|
|
else
|
|
{
|
|
rgNewDBProp[1].dwPropertyID = DBPROP_IRowsetRefresh;
|
|
rgNewDBProp[1].dwOptions = DBPROPOPTIONS_REQUIRED;
|
|
rgNewDBProp[1].colid = DB_NULLID;
|
|
rgNewDBProp[1].vValue.vt = VT_BOOL;
|
|
V_BOOL(&(rgNewDBProp[1].vValue)) = VARIANT_TRUE;
|
|
}
|
|
|
|
rgNewDBProp[2].dwPropertyID = DBPROP_IRowsetChange;
|
|
rgNewDBProp[2].dwOptions = DBPROPOPTIONS_REQUIRED;
|
|
rgNewDBProp[2].colid = DB_NULLID;
|
|
rgNewDBProp[2].vValue.vt = VT_BOOL;
|
|
V_BOOL(&(rgNewDBProp[2].vValue)) = VARIANT_TRUE;
|
|
|
|
NewPropSet.rgProperties = rgNewDBProp;
|
|
NewPropSet.cProperties = cProps;
|
|
NewPropSet.guidPropertySet = DBPROPSET_ROWSET;
|
|
|
|
SetRowsetProperties(&NewPropSet, 1);
|
|
|
|
//get a rowset
|
|
CHECK(((CTable *)m_pThisTestModule->m_pVoid)->CreateRowset( SELECT_UPDATEABLE,
|
|
IID_IRowset,
|
|
1,
|
|
&NewPropSet,
|
|
(IUnknown**)&m_pIRowset,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
0,
|
|
NULL,
|
|
NULL),S_OK);
|
|
|
|
|
|
if (!VerifyInterface(m_pIRowset, IID_IAccessor, ROWSET_INTERFACE,(IUnknown **)&m_pIAccessor))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
//create accessor on the rowset
|
|
CHECK(GetAccessorAndBindings( m_pIAccessor,
|
|
DBACCESSOR_ROWDATA,
|
|
&m_hAccessor,
|
|
&m_rgBindings,
|
|
&m_cBindings,
|
|
&m_cbRowSize,
|
|
DBPART_VALUE | DBPART_LENGTH | DBPART_STATUS,
|
|
NULLABLE_COLS_BOUND |UPDATEABLE_COLS_BOUND,
|
|
FORWARD,
|
|
NO_COLS_BY_REF,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
DBTYPE_EMPTY,
|
|
0,
|
|
NULL,
|
|
NULL,
|
|
NO_COLS_OWNED_BY_PROV,
|
|
DBPARAMIO_NOTPARAM,
|
|
NO_BLOB_COLS),
|
|
S_OK);
|
|
|
|
/////////////////////////////////////////////////////////
|
|
//Insert a null row into the table
|
|
/////////////////////////////////////////////////////////
|
|
m_pData = (BYTE *)PROVIDER_ALLOC(m_cbRowSize);
|
|
if (!m_pData)
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
memset(m_pData, 0, (size_t)m_cbRowSize);
|
|
|
|
for (j=0; j<m_cBindings; j++)
|
|
{
|
|
//set data buffer's status field
|
|
// *(DBSTATUS *)((DWORD)m_pData + m_rgBindings[j].obStatus) = DBSTATUS_S_ISNULL;
|
|
STATUS_BINDING(m_rgBindings[j],m_pData)=DBSTATUS_S_ISNULL;
|
|
}
|
|
|
|
//Get the row
|
|
if (!VerifyInterface(m_pIAccessor, IID_IRowsetChange, ROWSET_INTERFACE,
|
|
(IUnknown **)&pIRowsetChange))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
//get a row
|
|
m_pIRowset->RestartPosition(NULL);
|
|
if (!CHECK(m_pIRowset->GetNextRows(0, 0, 1, &cRowsObtained, &m_phRow),S_OK))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
//Make as many columns NULL as possible
|
|
hr = pIRowsetChange->SetData(m_hRow, m_hAccessor, m_pData);
|
|
{
|
|
if (DB_S_ERRORSOCCURRED == hr)
|
|
{
|
|
for (j=0; j<m_cBindings; j++)
|
|
{
|
|
// if (*(DBSTATUS *)((DWORD)m_pData + m_rgBindings[j].obStatus)!= DBSTATUS_S_ISNULL)
|
|
if (
|
|
DBSTATUS_S_ISNULL != STATUS_BINDING(m_rgBindings[j],m_pData)
|
|
)
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
}
|
|
fResults = TEST_SKIPPED;
|
|
goto CLEANUP;
|
|
}
|
|
if (S_OK!=hr)
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
//We only succeed if we get this far
|
|
fResults = TEST_PASS;
|
|
}
|
|
}
|
|
CLEANUP:
|
|
FreeProperties(&m_cPropSets, &m_rgPropSets);
|
|
|
|
if (m_pIRowset)
|
|
{
|
|
if (m_hRow != DB_NULL_HROW)
|
|
{
|
|
m_pIRowset->ReleaseRows(cRowsObtained, m_phRow, NULL, NULL, NULL);
|
|
m_hRow = DB_NULL_HROW;
|
|
}
|
|
}
|
|
if (m_pIAccessor)
|
|
{
|
|
if (m_hAccessor != DB_NULL_HACCESSOR)
|
|
{
|
|
m_pIAccessor->ReleaseAccessor(m_hAccessor, NULL);
|
|
}
|
|
}
|
|
|
|
if (m_rgBindings)
|
|
{
|
|
PROVIDER_FREE(m_rgBindings);
|
|
}
|
|
if (m_pData)
|
|
{
|
|
PROVIDER_FREE(m_pData);
|
|
}
|
|
|
|
SAFE_RELEASE(pIRowsetChange);
|
|
SAFE_RELEASE(m_pIRowset);
|
|
|
|
return fResults;
|
|
}
|
|
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(1)
|
|
//--------------------------------------------------------------------
|
|
// @mfunc Resynch on Null row
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCNullRowResynch::Variation_1()
|
|
{
|
|
BOOL fResults = FALSE;
|
|
BYTE *pRowsetData = NULL;
|
|
BYTE *pResynchRowsetData = NULL;
|
|
BYTE *pResynchVisibleData= NULL;
|
|
IRowsetResynch *pIRowResynch = NULL;
|
|
IRowsetRefresh *pIRowRefresh = NULL;
|
|
DBCOUNTITEM cRowsResynched = 0;
|
|
DBROWSTATUS *rgRowStatus = NULL;
|
|
HROW *rghRows = NULL;
|
|
DBCOUNTITEM cRowsObtained = 0;
|
|
|
|
if (m_eTI==TI_IRowsetResynch)
|
|
{
|
|
if (!VerifyInterface(m_pIAccessor, IID_IRowsetResynch, ROWSET_INTERFACE,(IUnknown **)&pIRowResynch))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (!VerifyInterface(m_pIAccessor, IID_IRowsetRefresh, ROWSET_INTERFACE,(IUnknown **)&pIRowRefresh))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
}
|
|
if (!VerifyInterface(m_pIAccessor, IID_IRowset, ROWSET_INTERFACE,(IUnknown **)&m_pIRowset))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
//create accessor on the rowset
|
|
if (!CHECK(GetAccessorAndBindings( m_pIAccessor,
|
|
DBACCESSOR_ROWDATA,
|
|
&m_hAccessor,
|
|
&m_rgBindings,
|
|
&m_cBindings,
|
|
&m_cbRowSize,
|
|
DBPART_VALUE | DBPART_LENGTH | DBPART_STATUS,
|
|
ALL_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))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
|
|
//alloc mem
|
|
pRowsetData = (BYTE *)PROVIDER_ALLOC(m_cbRowSize);
|
|
pResynchRowsetData = (BYTE *)PROVIDER_ALLOC(m_cbRowSize);
|
|
pResynchVisibleData = (BYTE *)PROVIDER_ALLOC(m_cbRowSize);
|
|
if (!pRowsetData || !pResynchRowsetData || !pResynchVisibleData)
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
memset(pRowsetData, 0, (size_t)m_cbRowSize);
|
|
memset(pResynchRowsetData, 0, (size_t)m_cbRowSize);
|
|
memset(pResynchVisibleData, 0, (size_t)m_cbRowSize);
|
|
|
|
/////////////////////////////////////////////////////////
|
|
// Make sure we can do all our resynching on null
|
|
// columns and it turns out the same as GetData
|
|
/////////////////////////////////////////////////////////
|
|
m_pIRowset->RestartPosition(NULL);
|
|
if (!CHECK(m_pIRowset->GetNextRows(0, 0, 1, &cRowsObtained, &m_phRow),S_OK))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
if (!CHECK(m_pIRowset->GetData(m_hRow, m_hAccessor, pRowsetData), S_OK))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
if (m_eTI==TI_IRowsetResynch)
|
|
{
|
|
if (!CHECK(pIRowResynch->GetVisibleData(m_hRow, m_hAccessor, pResynchVisibleData), S_OK))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
|
|
if (!CHECK(pIRowResynch->ResynchRows(0, NULL, &cRowsResynched, &rghRows, &rgRowStatus), S_OK))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (m_eTI==TI_IRowsetRefreshTRUE)
|
|
{
|
|
if (!CHECK(pIRowRefresh->RefreshVisibleData(DB_NULL_HCHAPTER, 0, NULL, TRUE, &cRowsResynched, &rghRows, &rgRowStatus), S_OK))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (!CHECK(pIRowRefresh->RefreshVisibleData(DB_NULL_HCHAPTER, 0, NULL, FALSE, &cRowsResynched, &rghRows, &rgRowStatus), S_OK))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
}
|
|
if (!CHECK(pIRowRefresh->GetLastVisibleData(m_hRow, m_hAccessor, pResynchVisibleData), S_OK))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
}
|
|
|
|
//We don't need the extra ref count ResynchRows Added
|
|
CHECK(m_pIRowset->ReleaseRows(cRowsResynched, rghRows, NULL, NULL, NULL), S_OK);
|
|
|
|
COMPARE(cRowsResynched, 1);
|
|
if (g_fNOCHANGE)
|
|
{
|
|
//no change was made here, if the provider can handle it, expect it
|
|
COMPARE(rgRowStatus[0], DBROWSTATUS_S_NOCHANGE);
|
|
}
|
|
else
|
|
{
|
|
COMPARE(rgRowStatus[0], DBROWSTATUS_S_OK);
|
|
}
|
|
|
|
if (!CHECK(m_pIRowset->GetData(m_hRow, m_hAccessor, pResynchRowsetData), S_OK))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
|
|
if (COMPARE(CompareBuffer(pRowsetData,pResynchVisibleData,m_cBindings,m_rgBindings,m_pIMalloc,FALSE,FALSE,COMPARE_ONLY),TRUE))
|
|
{
|
|
if (COMPARE(CompareBuffer(pResynchVisibleData,pResynchRowsetData,m_cBindings,m_rgBindings,m_pIMalloc,FALSE,FALSE,COMPARE_ONLY),TRUE))
|
|
{
|
|
fResults = TRUE;
|
|
}
|
|
}
|
|
CLEANUP:
|
|
if (m_pIRowset)
|
|
{
|
|
if (m_hRow != DB_NULL_HROW)
|
|
{
|
|
m_pIRowset->ReleaseRows(cRowsObtained, m_phRow, NULL, NULL, NULL);
|
|
m_hRow = DB_NULL_HROW;
|
|
}
|
|
}
|
|
|
|
if (m_pIAccessor)
|
|
{
|
|
if (m_hAccessor != DB_NULL_HACCESSOR)
|
|
{
|
|
m_pIAccessor->ReleaseAccessor(m_hAccessor, NULL);
|
|
}
|
|
}
|
|
|
|
if (m_rgBindings)
|
|
{
|
|
PROVIDER_FREE(m_rgBindings);
|
|
}
|
|
if (pRowsetData)
|
|
{
|
|
PROVIDER_FREE(pRowsetData);
|
|
}
|
|
if (pResynchRowsetData)
|
|
{
|
|
PROVIDER_FREE(pResynchRowsetData);
|
|
}
|
|
if (pResynchVisibleData)
|
|
{
|
|
PROVIDER_FREE(pResynchVisibleData);
|
|
}
|
|
if (rgRowStatus)
|
|
{
|
|
PROVIDER_FREE(rgRowStatus);
|
|
}
|
|
|
|
SAFE_RELEASE(pIRowResynch);
|
|
SAFE_RELEASE(pIRowRefresh);
|
|
SAFE_RELEASE(m_pIRowset);
|
|
|
|
if (rghRows)
|
|
PROVIDER_FREE(rghRows);
|
|
|
|
if (fResults)
|
|
return TEST_PASS;
|
|
else
|
|
return TEST_FAIL;
|
|
}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_TERMINATE_METHOD
|
|
//--------------------------------------------------------------------
|
|
// @mfunc TestCase Termination Routine
|
|
//
|
|
// @rdesc TRUE or FALSE
|
|
//
|
|
BOOL TCNullRowResynch::Terminate()
|
|
{
|
|
if (m_pITransactionLocal)
|
|
{
|
|
//clean up any changes this little kludge messed on the back end
|
|
m_pITransactionLocal->Abort(NULL,FALSE,FALSE);
|
|
}
|
|
SAFE_RELEASE(m_pITransactionLocal);
|
|
SAFE_RELEASE(m_pIAccessor);
|
|
|
|
// {{ TCW_TERM_BASECLASS_CHECK2
|
|
return(CRowsetObject::Terminate());
|
|
} // }}
|
|
// }}
|
|
// }}
|
|
|
|
|
|
|
|
|
|
// {{ TCW_TC_PROTOTYPE(TCMisc)
|
|
//*-----------------------------------------------------------------------
|
|
//| Test Case: TCMisc
|
|
//| Created: 10/04/99
|
|
//*-----------------------------------------------------------------------
|
|
|
|
//--------------------------------------------------------------------
|
|
// @mfunc TestCase Initialization Routine
|
|
//
|
|
// @rdesc TRUE or FALSE
|
|
//
|
|
BOOL TCMiscResynch::Init()
|
|
{
|
|
BOOL fResults = TEST_FAIL;
|
|
|
|
if (TEST_SKIPPED==fnInterfaceSupported())
|
|
{
|
|
return TEST_SKIPPED;
|
|
}
|
|
|
|
// {{ TCW_INIT_BASECLASS_CHECK
|
|
if(CRowsetObject::Init())
|
|
// }}
|
|
{
|
|
fResults = TEST_PASS;
|
|
}
|
|
|
|
return fResults;
|
|
}
|
|
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(1)
|
|
//--------------------------------------------------------------------
|
|
// @mfunc Resynch on a row with a computed column
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCMiscResynch::Variation_1()
|
|
{
|
|
BOOL fResults = FALSE;
|
|
HACCESSOR hAccessor = DB_NULL_HACCESSOR;
|
|
DBBINDING *rgBindings = NULL;
|
|
DBCOUNTITEM cBindings = 0;
|
|
DBLENGTH cbRowSize = 0;
|
|
BYTE *pRowsetData = NULL;
|
|
BYTE *pResynchRowsetData = NULL;
|
|
BYTE *pResynchVisibleData= NULL;
|
|
IRowsetResynch *pIRowResynch = NULL;
|
|
IRowsetRefresh *pIRowRefresh = NULL;
|
|
IRowset *pIRowset = NULL;
|
|
IAccessor *pIAccessor = NULL;
|
|
DBCOUNTITEM cRowsResynched = 0;
|
|
DBROWSTATUS *rgRowStatus = NULL;
|
|
HROW *rghRows = NULL;
|
|
DBCOUNTITEM cRowsObtained = 0;
|
|
const ULONG cProps = 3;
|
|
DBPROP rgNewDBProp[cProps];
|
|
DBPROPSET NewPropSet;
|
|
HRESULT hr;
|
|
HROW hRow = DB_NULL_HROW;
|
|
HROW *phRow = &hRow;
|
|
|
|
|
|
//Set up our rowset properties
|
|
rgNewDBProp[0].dwPropertyID = DBPROP_UPDATABILITY;
|
|
rgNewDBProp[0].dwOptions = DBPROPOPTIONS_REQUIRED;
|
|
rgNewDBProp[0].colid = DB_NULLID;
|
|
rgNewDBProp[0].vValue.vt = VT_I4;
|
|
rgNewDBProp[0].vValue.lVal = DBPROPVAL_UP_INSERT | DBPROPVAL_UP_CHANGE | DBPROPVAL_UP_DELETE;
|
|
|
|
if (m_eTI==TI_IRowsetResynch)
|
|
{
|
|
rgNewDBProp[1].dwPropertyID = DBPROP_IRowsetResynch;
|
|
rgNewDBProp[1].dwOptions = DBPROPOPTIONS_REQUIRED;
|
|
rgNewDBProp[1].colid = DB_NULLID;
|
|
rgNewDBProp[1].vValue.vt = VT_BOOL;
|
|
V_BOOL(&(rgNewDBProp[1].vValue)) = VARIANT_TRUE;
|
|
}
|
|
else
|
|
{
|
|
rgNewDBProp[1].dwPropertyID = DBPROP_IRowsetRefresh;
|
|
rgNewDBProp[1].dwOptions = DBPROPOPTIONS_REQUIRED;
|
|
rgNewDBProp[1].colid = DB_NULLID;
|
|
rgNewDBProp[1].vValue.vt = VT_BOOL;
|
|
V_BOOL(&(rgNewDBProp[1].vValue)) = VARIANT_TRUE;
|
|
}
|
|
|
|
rgNewDBProp[2].dwPropertyID = DBPROP_IRowsetChange;
|
|
rgNewDBProp[2].dwOptions = DBPROPOPTIONS_REQUIRED;
|
|
rgNewDBProp[2].colid = DB_NULLID;
|
|
rgNewDBProp[2].vValue.vt = VT_BOOL;
|
|
V_BOOL(&(rgNewDBProp[2].vValue)) = VARIANT_TRUE;
|
|
|
|
NewPropSet.rgProperties = rgNewDBProp;
|
|
NewPropSet.cProperties = cProps;
|
|
NewPropSet.guidPropertySet = DBPROPSET_ROWSET;
|
|
|
|
//get a rowset
|
|
hr = ((CTable *)m_pThisTestModule->m_pVoid)->CreateRowset( SELECT_COMPUTEDCOLLIST,
|
|
IID_IRowset,
|
|
1,
|
|
&NewPropSet,
|
|
(IUnknown**)&pIRowset,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
0,
|
|
NULL,
|
|
NULL);
|
|
|
|
if (m_eTI==TI_IRowsetResynch)
|
|
{
|
|
if (!VerifyInterface(pIRowset, IID_IRowsetResynch, ROWSET_INTERFACE,(IUnknown **)&pIRowResynch))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (!VerifyInterface(pIRowset, IID_IRowsetRefresh, ROWSET_INTERFACE,(IUnknown **)&pIRowRefresh))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
}
|
|
if (!VerifyInterface(pIRowset, IID_IAccessor, ROWSET_INTERFACE,(IUnknown **)&pIAccessor))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
//create accessor on the rowset
|
|
if (!CHECK(GetAccessorAndBindings( pIAccessor,
|
|
DBACCESSOR_ROWDATA,
|
|
&hAccessor,
|
|
&rgBindings,
|
|
&cBindings,
|
|
&cbRowSize,
|
|
DBPART_VALUE | DBPART_LENGTH | DBPART_STATUS,
|
|
ALL_COLS_BOUND,
|
|
FORWARD,
|
|
NO_COLS_BY_REF,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
DBTYPE_EMPTY,
|
|
0,
|
|
NULL,
|
|
NULL,
|
|
NO_COLS_OWNED_BY_PROV,
|
|
DBPARAMIO_NOTPARAM,
|
|
NO_BLOB_COLS),
|
|
S_OK))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
|
|
//alloc mem
|
|
pRowsetData = (BYTE *)PROVIDER_ALLOC(cbRowSize);
|
|
pResynchRowsetData = (BYTE *)PROVIDER_ALLOC(cbRowSize);
|
|
pResynchVisibleData = (BYTE *)PROVIDER_ALLOC(cbRowSize);
|
|
if (!pRowsetData || !pResynchRowsetData || !pResynchVisibleData)
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
memset(pRowsetData, 0, (size_t)cbRowSize);
|
|
memset(pResynchRowsetData, 0, (size_t)cbRowSize);
|
|
memset(pResynchVisibleData, 0, (size_t)cbRowSize);
|
|
|
|
//get a row and make a change on it
|
|
CHECK(pIRowset->GetNextRows(0, 0, 1, &cRowsObtained, &phRow),S_OK);
|
|
|
|
CHECK(pIRowset->GetData(hRow, hAccessor, pRowsetData), S_OK);
|
|
|
|
if (m_eTI==TI_IRowsetResynch)
|
|
{
|
|
if (!CHECK(pIRowResynch->GetVisibleData(hRow, hAccessor, pResynchVisibleData), S_OK))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
|
|
if (!CHECK(pIRowResynch->ResynchRows(0, NULL, &cRowsResynched, &rghRows, &rgRowStatus), S_OK))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (m_eTI==TI_IRowsetRefreshTRUE)
|
|
{
|
|
if (!CHECK(pIRowRefresh->RefreshVisibleData(DB_NULL_HCHAPTER, 0, NULL, TRUE, &cRowsResynched, &rghRows, &rgRowStatus), S_OK))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (!CHECK(pIRowRefresh->RefreshVisibleData(DB_NULL_HCHAPTER, 0, NULL, FALSE, &cRowsResynched, &rghRows, &rgRowStatus), S_OK))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
}
|
|
if (!CHECK(pIRowRefresh->GetLastVisibleData(hRow, hAccessor, pResynchVisibleData), S_OK))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
}
|
|
|
|
//We don't need the extra ref count ResynchRows Added
|
|
CHECK(pIRowset->ReleaseRows(cRowsResynched, rghRows, NULL, NULL, NULL), S_OK);
|
|
|
|
COMPARE(cRowsResynched, 1);
|
|
|
|
if (g_fNOCHANGE)
|
|
{
|
|
//no change was made here, if the provider can handle it, expect it
|
|
COMPARE(rgRowStatus[0], DBROWSTATUS_S_NOCHANGE);
|
|
}
|
|
else
|
|
{
|
|
COMPARE(rgRowStatus[0], DBROWSTATUS_S_OK);
|
|
}
|
|
|
|
if (!CHECK(pIRowset->GetData(hRow, hAccessor, pResynchRowsetData), S_OK))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
|
|
if (COMPARE(CompareBuffer(pRowsetData,pResynchVisibleData,cBindings,rgBindings,m_pIMalloc,FALSE,FALSE,COMPARE_ONLY),TRUE))
|
|
{
|
|
if (COMPARE(CompareBuffer(pResynchVisibleData,pResynchRowsetData,cBindings,rgBindings,m_pIMalloc,FALSE,FALSE,COMPARE_ONLY),TRUE))
|
|
{
|
|
fResults = TRUE;
|
|
}
|
|
}
|
|
CLEANUP:
|
|
if (pIRowset)
|
|
{
|
|
if (hRow != DB_NULL_HROW)
|
|
{
|
|
pIRowset->ReleaseRows(cRowsObtained, phRow, NULL, NULL, NULL);
|
|
hRow = DB_NULL_HROW;
|
|
}
|
|
if (pIRowset)
|
|
{
|
|
pIRowset->Release();
|
|
pIRowset = NULL;
|
|
}
|
|
}
|
|
|
|
if (pIAccessor)
|
|
{
|
|
if (hAccessor != DB_NULL_HACCESSOR)
|
|
{
|
|
pIAccessor->ReleaseAccessor(hAccessor, NULL);
|
|
}
|
|
}
|
|
|
|
if (rgBindings)
|
|
{
|
|
PROVIDER_FREE(rgBindings);
|
|
}
|
|
if (pRowsetData)
|
|
{
|
|
PROVIDER_FREE(pRowsetData);
|
|
}
|
|
if (pResynchRowsetData)
|
|
{
|
|
PROVIDER_FREE(pResynchRowsetData);
|
|
}
|
|
if (pResynchVisibleData)
|
|
{
|
|
PROVIDER_FREE(pResynchVisibleData);
|
|
}
|
|
if (rgRowStatus)
|
|
{
|
|
PROVIDER_FREE(rgRowStatus);
|
|
}
|
|
if (pIRowResynch)
|
|
{
|
|
pIRowResynch->Release();
|
|
pIRowResynch = NULL;
|
|
}
|
|
if (rghRows)
|
|
{
|
|
PROVIDER_FREE(rghRows);
|
|
}
|
|
|
|
SAFE_RELEASE(pIAccessor);
|
|
SAFE_RELEASE(pIRowRefresh);
|
|
SAFE_RELEASE(pIRowResynch);
|
|
SAFE_RELEASE(pIRowset);
|
|
|
|
if (fResults)
|
|
return TEST_PASS;
|
|
else
|
|
return TEST_FAIL;
|
|
}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(2)
|
|
//--------------------------------------------------------------------
|
|
// @mfunc different accessors
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCMiscResynch::Variation_2()
|
|
{
|
|
BOOL fResults = FALSE;
|
|
HACCESSOR hAccessor = DB_NULL_HACCESSOR;
|
|
DBBINDING *rgBindings = NULL;
|
|
DBCOUNTITEM cBindings = 0;
|
|
DBLENGTH cbRowSize = 0;
|
|
BYTE *pData = NULL;
|
|
BYTE *pData2 = NULL;
|
|
HACCESSOR hAccessor2 = DB_NULL_HACCESSOR;
|
|
DBBINDING *rgBindings2 = NULL;
|
|
DBCOUNTITEM cBindings2 = 0;
|
|
DBLENGTH cbRowSize2 = 0;
|
|
BYTE *pRowsetData = NULL;
|
|
BYTE *pResynchRowsetData = NULL;
|
|
BYTE *pVisibleData = NULL;
|
|
IRowsetResynch *pIRowResynch = NULL;
|
|
IRowsetRefresh *pIRowRefresh = NULL;
|
|
IAccessor *pIAccessor = NULL;
|
|
IRowset *pIRowset = NULL;
|
|
DBCOUNTITEM cRowsResynched = 0;
|
|
DBROWSTATUS *rgRowStatus = NULL;
|
|
HROW *rghRows = NULL;
|
|
DBCOUNTITEM cRowsObtained = 0;
|
|
const ULONG cProps = 3;
|
|
DBPROP rgNewDBProp[cProps];
|
|
DBPROPSET NewPropSet;
|
|
IRowsetChange *pIRowsetChange = NULL;
|
|
ITransactionLocal *pITransactionLocal = NULL;
|
|
HRESULT hr;
|
|
HROW hRow = DB_NULL_HROW;
|
|
HROW *phRow = &hRow;
|
|
|
|
//Get IRowset on the object
|
|
if (!VerifyInterface((IUnknown *)m_pThisTestModule->m_pIUnknown2,
|
|
IID_ITransactionLocal, SESSION_INTERFACE, (IUnknown **)&pITransactionLocal))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
g_ulLastActualInsert++;
|
|
pITransactionLocal->StartTransaction(ISOLATIONLEVEL_READCOMMITTED, 0, NULL, NULL);
|
|
|
|
//Set up our rowset properties
|
|
rgNewDBProp[0].dwPropertyID = DBPROP_UPDATABILITY;
|
|
rgNewDBProp[0].dwOptions = DBPROPOPTIONS_REQUIRED;
|
|
rgNewDBProp[0].colid = DB_NULLID;
|
|
rgNewDBProp[0].vValue.vt = VT_I4;
|
|
rgNewDBProp[0].vValue.lVal = DBPROPVAL_UP_INSERT | DBPROPVAL_UP_CHANGE | DBPROPVAL_UP_DELETE;
|
|
|
|
if (m_eTI==TI_IRowsetResynch)
|
|
{
|
|
rgNewDBProp[1].dwPropertyID = DBPROP_IRowsetResynch;
|
|
rgNewDBProp[1].dwOptions = DBPROPOPTIONS_REQUIRED;
|
|
rgNewDBProp[1].colid = DB_NULLID;
|
|
rgNewDBProp[1].vValue.vt = VT_BOOL;
|
|
V_BOOL(&(rgNewDBProp[1].vValue)) = VARIANT_TRUE;
|
|
}
|
|
else
|
|
{
|
|
rgNewDBProp[1].dwPropertyID = DBPROP_IRowsetRefresh;
|
|
rgNewDBProp[1].dwOptions = DBPROPOPTIONS_REQUIRED;
|
|
rgNewDBProp[1].colid = DB_NULLID;
|
|
rgNewDBProp[1].vValue.vt = VT_BOOL;
|
|
V_BOOL(&(rgNewDBProp[1].vValue)) = VARIANT_TRUE;
|
|
}
|
|
|
|
rgNewDBProp[2].dwPropertyID = DBPROP_IRowsetChange;
|
|
rgNewDBProp[2].dwOptions = DBPROPOPTIONS_REQUIRED;
|
|
rgNewDBProp[2].colid = DB_NULLID;
|
|
rgNewDBProp[2].vValue.vt = VT_BOOL;
|
|
V_BOOL(&(rgNewDBProp[2].vValue)) = VARIANT_TRUE;
|
|
|
|
NewPropSet.rgProperties = rgNewDBProp;
|
|
NewPropSet.cProperties = cProps;
|
|
NewPropSet.guidPropertySet = DBPROPSET_ROWSET;
|
|
|
|
//get a rowset
|
|
hr = ((CTable *)m_pThisTestModule->m_pVoid)->CreateRowset( USE_OPENROWSET,
|
|
IID_IRowset,
|
|
1,
|
|
&NewPropSet,
|
|
(IUnknown**)&pIRowset,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
0,
|
|
NULL,
|
|
NULL);
|
|
|
|
if (m_eTI==TI_IRowsetResynch)
|
|
{
|
|
if (!VerifyInterface(pIRowset, IID_IRowsetResynch, ROWSET_INTERFACE,(IUnknown **)&pIRowResynch))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (!VerifyInterface(pIRowset, IID_IRowsetRefresh, ROWSET_INTERFACE,(IUnknown **)&pIRowRefresh))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
}
|
|
|
|
if (!VerifyInterface(pIRowset, IID_IAccessor, ROWSET_INTERFACE,(IUnknown **)&pIAccessor))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
//create accessor on the rowset
|
|
if (!CHECK(GetAccessorAndBindings( pIAccessor,
|
|
DBACCESSOR_ROWDATA,
|
|
&hAccessor,
|
|
&rgBindings,
|
|
&cBindings,
|
|
&cbRowSize,
|
|
DBPART_VALUE | DBPART_LENGTH | DBPART_STATUS,
|
|
ALL_COLS_BOUND,
|
|
FORWARD,
|
|
NO_COLS_BY_REF,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
DBTYPE_EMPTY,
|
|
0,
|
|
NULL,
|
|
NULL,
|
|
NO_COLS_OWNED_BY_PROV,
|
|
DBPARAMIO_NOTPARAM,
|
|
NO_BLOB_COLS),
|
|
S_OK))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
//create a 2nd accessor on the rowset
|
|
if (!CHECK(GetAccessorAndBindings( pIAccessor,
|
|
DBACCESSOR_ROWDATA,
|
|
&hAccessor2,
|
|
&rgBindings2,
|
|
&cBindings2,
|
|
&cbRowSize2,
|
|
DBPART_VALUE | DBPART_LENGTH | DBPART_STATUS,
|
|
UPDATEABLE_COLS_BOUND,
|
|
FORWARD,
|
|
NO_COLS_BY_REF,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
DBTYPE_EMPTY,
|
|
0,
|
|
NULL,
|
|
NULL,
|
|
NO_COLS_OWNED_BY_PROV,
|
|
DBPARAMIO_NOTPARAM,
|
|
NO_BLOB_COLS),
|
|
S_OK))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
|
|
//alloc mem
|
|
pRowsetData = (BYTE *)PROVIDER_ALLOC(cbRowSize);
|
|
pResynchRowsetData = (BYTE *)PROVIDER_ALLOC(cbRowSize);
|
|
pVisibleData = (BYTE *)PROVIDER_ALLOC(cbRowSize);
|
|
if (!pRowsetData || !pResynchRowsetData || !pVisibleData)
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
memset(pRowsetData, 0, (size_t)cbRowSize);
|
|
memset(pResynchRowsetData, 0, (size_t)cbRowSize);
|
|
memset(pVisibleData, 0, (size_t)cbRowSize);
|
|
|
|
//Set data for all columns
|
|
TESTC_(FillInputBindings( ((CTable *)m_pThisTestModule->m_pVoid),
|
|
DBACCESSOR_ROWDATA,
|
|
cBindings,
|
|
rgBindings,
|
|
&pData,
|
|
g_ulLastActualInsert,
|
|
((CTable *)m_pThisTestModule->m_pVoid)->CountColumnsOnTable(),
|
|
m_rgTableColOrds), S_OK);
|
|
|
|
//create another buffer based on the same seed with the 2nd accessor
|
|
TESTC_(FillInputBindings( ((CTable *)m_pThisTestModule->m_pVoid),
|
|
DBACCESSOR_ROWDATA,
|
|
cBindings2,
|
|
rgBindings2,
|
|
&pData2,
|
|
g_ulLastActualInsert,
|
|
((CTable *)m_pThisTestModule->m_pVoid)->CountColumnsOnTable(),
|
|
m_rgTableColOrds), S_OK);
|
|
|
|
//get a row and make a change on it
|
|
CHECK(pIRowset->GetNextRows(0, 0, 1, &cRowsObtained, &phRow),S_OK);
|
|
if (!VerifyInterface(pIRowset, IID_IRowsetChange, ROWSET_INTERFACE,(IUnknown **)&pIRowsetChange))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
//change a row, updatable cols
|
|
CHECK(pIRowsetChange->SetData(phRow[0], hAccessor, pData), S_OK);
|
|
|
|
//now get data with 2nd accessor
|
|
CHECK(pIRowset->GetData(hRow, hAccessor2, pRowsetData), S_OK);
|
|
|
|
//GetVisible with the 2nd
|
|
//check if the SetData did a delete/insert underneath first off
|
|
if (m_eTI==TI_IRowsetResynch)
|
|
{
|
|
hr = pIRowResynch->GetVisibleData(hRow, hAccessor2, pVisibleData);
|
|
if (DB_E_DELETEDROW==hr)
|
|
{
|
|
if (!CHECK(pIRowResynch->ResynchRows(0, NULL, &cRowsResynched, &rghRows, &rgRowStatus), DB_E_ERRORSOCCURRED))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
COMPARE(1,cRowsResynched);
|
|
COMPARE(rgRowStatus[0], DBROWSTATUS_E_DELETED);
|
|
fResults = TRUE;
|
|
goto CLEANUP;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (g_fVisualCache)
|
|
{
|
|
CHECK(pIRowRefresh->GetLastVisibleData(hRow, hAccessor2, pVisibleData),S_OK);
|
|
}
|
|
else
|
|
{
|
|
hr = pIRowRefresh->GetLastVisibleData(hRow, hAccessor2, pVisibleData);
|
|
if (DB_E_DELETEDROW==hr)
|
|
{
|
|
if (!CHECK(pIRowResynch->ResynchRows(0, NULL, &cRowsResynched, &rghRows, &rgRowStatus), DB_E_ERRORSOCCURRED))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
COMPARE(1,cRowsResynched);
|
|
COMPARE(rgRowStatus[0], DBROWSTATUS_E_DELETED);
|
|
fResults = TRUE;
|
|
goto CLEANUP;
|
|
}
|
|
}
|
|
}
|
|
COMPARE(hr,S_OK);
|
|
|
|
//resynch and check againg for deletedrow in case there was a visual cache
|
|
if (m_eTI==TI_IRowsetResynch)
|
|
{
|
|
if (!CHECK(pIRowResynch->ResynchRows(0, NULL, &cRowsResynched, &rghRows, &rgRowStatus), S_OK))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (m_eTI==TI_IRowsetRefreshTRUE)
|
|
{
|
|
hr = pIRowRefresh->RefreshVisibleData(DB_NULL_HCHAPTER, 0, NULL, TRUE, &cRowsResynched, &rghRows, &rgRowStatus);
|
|
}
|
|
else
|
|
{
|
|
hr = pIRowRefresh->RefreshVisibleData(DB_NULL_HCHAPTER, 0, NULL, FALSE, &cRowsResynched, &rghRows, &rgRowStatus);
|
|
}
|
|
}
|
|
|
|
if (DB_E_ERRORSOCCURRED==hr)
|
|
{
|
|
COMPARE(rgRowStatus[0], DBROWSTATUS_E_DELETED);
|
|
fResults = TRUE;
|
|
goto CLEANUP;
|
|
}
|
|
|
|
//don't need the extra ref count ResynchRows Added
|
|
CHECK(pIRowset->ReleaseRows(cRowsResynched, rghRows, NULL, NULL, NULL), S_OK);
|
|
//one active row
|
|
COMPARE(cRowsResynched, 1);
|
|
|
|
if (g_fNOCHANGE)
|
|
{
|
|
//no change was made here (the rowset changed it itself),
|
|
COMPARE(rgRowStatus[0], DBROWSTATUS_S_NOCHANGE);
|
|
}
|
|
else
|
|
{
|
|
COMPARE(rgRowStatus[0], DBROWSTATUS_S_OK);
|
|
}
|
|
|
|
if (!CHECK(pIRowset->GetData(hRow, hAccessor2, pResynchRowsetData), S_OK))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
|
|
//check that the buffer all have the 2nd accesor's version of the new buffer
|
|
COMPARE(CompareBuffer(pRowsetData,pData2,cBindings2,rgBindings2,m_pIMalloc,TRUE,FALSE,COMPARE_ONLY),TRUE);
|
|
COMPARE(CompareBuffer(pRowsetData,pVisibleData,cBindings2,rgBindings2,m_pIMalloc,FALSE,FALSE,COMPARE_ONLY),TRUE);
|
|
COMPARE(CompareBuffer(pVisibleData,pResynchRowsetData,cBindings2,rgBindings2,m_pIMalloc,FALSE,FALSE,COMPARE_ONLY),TRUE);
|
|
|
|
fResults = TRUE;
|
|
CLEANUP:
|
|
if (pITransactionLocal)
|
|
{
|
|
//clean up any changes this little kludge messed on the back end
|
|
pITransactionLocal->Abort(NULL,FALSE,FALSE);
|
|
}
|
|
g_ulLastActualInsert--;
|
|
|
|
if (pIRowset)
|
|
{
|
|
if (hRow != DB_NULL_HROW)
|
|
{
|
|
pIRowset->ReleaseRows(cRowsObtained, phRow, NULL, NULL, NULL);
|
|
hRow = DB_NULL_HROW;
|
|
}
|
|
}
|
|
|
|
if (pIAccessor)
|
|
{
|
|
if (hAccessor != DB_NULL_HACCESSOR)
|
|
{
|
|
pIAccessor->ReleaseAccessor(hAccessor, NULL);
|
|
}
|
|
if (hAccessor2 != DB_NULL_HACCESSOR)
|
|
{
|
|
pIAccessor->ReleaseAccessor(hAccessor2, NULL);
|
|
}
|
|
}
|
|
|
|
if (pRowsetData)
|
|
{
|
|
PROVIDER_FREE(pRowsetData);
|
|
}
|
|
if (pResynchRowsetData)
|
|
{
|
|
PROVIDER_FREE(pResynchRowsetData);
|
|
}
|
|
if (pVisibleData)
|
|
{
|
|
PROVIDER_FREE(pVisibleData);
|
|
}
|
|
//Cleanup any out of line memory allocated in FillInputBindings and pData
|
|
ReleaseInputBindingsMemory(cBindings, rgBindings, pData, TRUE);
|
|
if (rgBindings)
|
|
{
|
|
PROVIDER_FREE(rgBindings);
|
|
}
|
|
//Cleanup any out of line memory allocated in FillInputBindings and pData
|
|
ReleaseInputBindingsMemory(cBindings2, rgBindings2, pData2, TRUE);
|
|
if (rgBindings2)
|
|
{
|
|
PROVIDER_FREE(rgBindings2);
|
|
}
|
|
if (rgRowStatus)
|
|
{
|
|
PROVIDER_FREE(rgRowStatus);
|
|
}
|
|
if (rghRows)
|
|
{
|
|
PROVIDER_FREE(rghRows);
|
|
}
|
|
|
|
SAFE_RELEASE(pIRowsetChange);
|
|
SAFE_RELEASE(pITransactionLocal);
|
|
SAFE_RELEASE(pIAccessor);
|
|
SAFE_RELEASE(pIRowRefresh);
|
|
SAFE_RELEASE(pIRowResynch);
|
|
SAFE_RELEASE(pIRowset);
|
|
|
|
if (fResults)
|
|
return TEST_PASS;
|
|
else
|
|
return TEST_FAIL;
|
|
}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(3)
|
|
//--------------------------------------------------------------------
|
|
// @mfunc OTHERUPDATEDELETE - FALSE
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCMiscResynch::Variation_3()
|
|
{
|
|
HACCESSOR hAccessor1 = DB_NULL_HACCESSOR;
|
|
HACCESSOR hAccessor2 = DB_NULL_HACCESSOR;
|
|
IAccessor *pIAccessor1 = NULL;
|
|
IAccessor *pIAccessor2 = NULL;
|
|
DBBINDING *rgBindings = NULL;
|
|
DBCOUNTITEM cBindings = 0;
|
|
ITransactionLocal *pITransactionLocal = NULL;
|
|
IRowsetChange *pIRowsetChange = NULL;
|
|
IRowsetRefresh *pIRowsetRefresh= NULL;
|
|
IRowsetResynch *pIRowsetResynch= NULL;
|
|
IRowset *pIRowset1 = NULL;
|
|
IRowset *pIRowset2 = NULL;
|
|
const ULONG cProps = 4;
|
|
DBPROPSET DBPropSet;
|
|
DBPROP DBProp[cProps];
|
|
HRESULT hr = S_OK;
|
|
BYTE *pData = NULL;
|
|
const ULONG cRows = 1;
|
|
HROW rghRows1[cRows];
|
|
HROW *phRows1 = rghRows1;
|
|
HROW rghRows2[cRows];
|
|
HROW *phRows2 = rghRows2;
|
|
BOOL fResult = TEST_FAIL;
|
|
DBCOUNTITEM cRowsObtained = 1;
|
|
IMalloc *pIMalloc = NULL;
|
|
DBLENGTH cRowSize = 0;
|
|
DBCOUNTITEM cRowsResynched = 0;
|
|
DBROWSTATUS *rgReRowStatus = NULL;
|
|
HROW *rghReRows = NULL;
|
|
|
|
|
|
//Struct for set properties
|
|
DBPropSet.guidPropertySet = DBPROPSET_ROWSET;
|
|
DBPropSet.rgProperties = DBProp;
|
|
DBPropSet.cProperties = cProps;
|
|
|
|
DBProp[0].dwPropertyID = DBPROP_IRowsetChange;
|
|
DBProp[0].dwOptions = DBPROPOPTIONS_REQUIRED;
|
|
DBProp[0].colid = DB_NULLID;
|
|
DBProp[0].vValue.vt = VT_BOOL;
|
|
V_BOOL(&(DBProp[0].vValue)) = VARIANT_TRUE;
|
|
|
|
DBProp[1].dwPropertyID = DBPROP_UPDATABILITY;
|
|
DBProp[1].dwOptions = 0;
|
|
DBProp[1].colid = DB_NULLID;
|
|
DBProp[1].vValue.vt = VT_I4;
|
|
DBProp[1].vValue.lVal = DBPROPVAL_UP_CHANGE | DBPROPVAL_UP_DELETE | DBPROPVAL_UP_INSERT;
|
|
|
|
if(g_fRefresh)
|
|
{
|
|
DBProp[2].dwPropertyID = DBPROP_IRowsetRefresh;
|
|
DBProp[2].dwOptions = 0;
|
|
DBProp[2].colid = DB_NULLID;
|
|
DBProp[2].vValue.vt = VT_BOOL;
|
|
V_BOOL(&(DBProp[2].vValue)) = VARIANT_TRUE;
|
|
}
|
|
else
|
|
{
|
|
DBProp[2].dwPropertyID = DBPROP_IRowsetResynch;
|
|
DBProp[2].dwOptions = 0;
|
|
DBProp[2].colid = DB_NULLID;
|
|
DBProp[2].vValue.vt = VT_BOOL;
|
|
V_BOOL(&(DBProp[2].vValue)) = VARIANT_TRUE;
|
|
}
|
|
|
|
DBProp[3].dwPropertyID = DBPROP_OTHERUPDATEDELETE;
|
|
DBProp[3].dwOptions = DBPROPOPTIONS_REQUIRED;
|
|
DBProp[3].colid = DB_NULLID;
|
|
DBProp[3].vValue.vt = VT_BOOL;
|
|
V_BOOL(&(DBProp[3].vValue)) = VARIANT_FALSE;
|
|
|
|
//Get IRowset on the object
|
|
if (!VerifyInterface((IUnknown *)m_pThisTestModule->m_pIUnknown2,
|
|
IID_ITransactionLocal, SESSION_INTERFACE, (IUnknown **)&pITransactionLocal))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
pITransactionLocal->StartTransaction(ISOLATIONLEVEL_READCOMMITTED, 0, NULL, NULL);
|
|
|
|
//get 2 rowsets
|
|
hr = ((CTable *)m_pThisTestModule->m_pVoid)->CreateRowset( USE_OPENROWSET,
|
|
IID_IRowset,
|
|
1,
|
|
&DBPropSet,
|
|
(IUnknown**)&pIRowset1,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
0,
|
|
NULL,
|
|
NULL);
|
|
|
|
//if IRowsetRefresh conflicts with DBPROP_OTHERUPDATEDELETE-FALSE skip this
|
|
if (hr != S_OK)
|
|
{
|
|
fResult = TEST_SKIPPED;
|
|
goto CLEANUP;
|
|
}
|
|
|
|
hr = ((CTable *)m_pThisTestModule->m_pVoid)->CreateRowset( USE_OPENROWSET,
|
|
IID_IRowset,
|
|
1,
|
|
&DBPropSet,
|
|
(IUnknown**)&pIRowset2,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
0,
|
|
NULL,
|
|
NULL);
|
|
|
|
//if IRowsetRefresh conflicts with DBPROP_OTHERUPDATEDELETE-FALSE skip this
|
|
if (hr != S_OK)
|
|
{
|
|
fResult = TEST_SKIPPED;
|
|
goto CLEANUP;
|
|
}
|
|
|
|
//Get accessor on the object
|
|
if (!VerifyInterface(pIRowset1, IID_IAccessor, ROWSET_INTERFACE, (IUnknown **)&pIAccessor1))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
|
|
//Get accessor on the object
|
|
if (!VerifyInterface(pIRowset2, IID_IAccessor, ROWSET_INTERFACE, (IUnknown **)&pIAccessor2))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
|
|
TESTC_(GetAccessorAndBindings( pIAccessor1,
|
|
DBACCESSOR_ROWDATA,
|
|
&hAccessor1,
|
|
&rgBindings,
|
|
&cBindings,
|
|
&cRowSize,
|
|
DBPART_VALUE | DBPART_LENGTH | DBPART_STATUS,
|
|
ALL_COLS_BOUND,
|
|
FORWARD,
|
|
NO_COLS_BY_REF,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
DBTYPE_EMPTY,
|
|
0,
|
|
NULL,
|
|
NULL,
|
|
NO_COLS_OWNED_BY_PROV,
|
|
DBPARAMIO_NOTPARAM,
|
|
NO_BLOB_COLS),S_OK);
|
|
|
|
|
|
//alloc here just so test has it to free for ReleaseInputBindingsMemory
|
|
pData = (BYTE *)PROVIDER_ALLOC(cRowSize);
|
|
//Cleanup any out of line memory allocated in FillInputBindings and pData
|
|
ReleaseInputBindingsMemory(cBindings, rgBindings, pData, TRUE);
|
|
if (rgBindings)
|
|
{
|
|
PROVIDER_FREE(rgBindings);
|
|
}
|
|
pData = NULL;
|
|
|
|
TESTC_(GetAccessorAndBindings( pIAccessor2,
|
|
DBACCESSOR_ROWDATA,
|
|
&hAccessor2,
|
|
&rgBindings,
|
|
&cBindings,
|
|
NULL,
|
|
DBPART_VALUE | DBPART_LENGTH | DBPART_STATUS,
|
|
ALL_COLS_BOUND,
|
|
FORWARD,
|
|
NO_COLS_BY_REF,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
DBTYPE_EMPTY,
|
|
0,
|
|
NULL,
|
|
NULL,
|
|
NO_COLS_OWNED_BY_PROV,
|
|
DBPARAMIO_NOTPARAM,
|
|
NO_BLOB_COLS),S_OK);
|
|
|
|
//Set data for all columns
|
|
TESTC_(FillInputBindings( ((CTable *)m_pThisTestModule->m_pVoid),
|
|
DBACCESSOR_ROWDATA,
|
|
cBindings,
|
|
rgBindings,
|
|
&pData,
|
|
g_ulLastActualInsert+1,
|
|
((CTable *)m_pThisTestModule->m_pVoid)->CountColumnsOnTable(),
|
|
m_rgTableColOrds), S_OK);
|
|
|
|
//Get IRowsetChange on the object
|
|
if (!VerifyInterface(pIRowset1, IID_IRowsetChange, ROWSET_INTERFACE, (IUnknown **)&pIRowsetChange))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
|
|
|
|
//get the first row through the 1st rowset
|
|
TESTC_(pIRowset1->RestartPosition(NULL), S_OK);
|
|
TESTC_(pIRowset1->GetNextRows(NULL, 0, 1, &cRowsObtained, &phRows1),S_OK);
|
|
|
|
//get the first row through the 2nd rowset
|
|
TESTC_(pIRowset2->RestartPosition(NULL), S_OK);
|
|
TESTC_(pIRowset2->GetNextRows(NULL, 0, 1, &cRowsObtained, &phRows2),S_OK);
|
|
|
|
//change the data through the first rowset
|
|
TESTC_(pIRowsetChange->SetData(phRows1[0], hAccessor1, pData), S_OK);
|
|
TESTC_(pIRowset1->ReleaseRows(cRowsObtained, phRows1, NULL, NULL, NULL), S_OK);
|
|
|
|
//get refresh(or resynch) from rowset2
|
|
if(g_fRefresh)
|
|
{
|
|
if (!VerifyInterface(pIRowset2, IID_IRowsetRefresh, ROWSET_INTERFACE, (IUnknown **)&pIRowsetRefresh))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (!VerifyInterface(pIRowset2, IID_IRowsetResynch, ROWSET_INTERFACE, (IUnknown **)&pIRowsetResynch))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
}
|
|
|
|
//get the visible data from the 2nd rowset
|
|
if (g_fRefresh)
|
|
{
|
|
//refresh the data from the rowset
|
|
TESTC_(pIRowsetRefresh->RefreshVisibleData(DB_NULL_HCHAPTER,1, &phRows2[0], TRUE, &cRowsResynched, &rghReRows, &rgReRowStatus),S_OK);
|
|
TESTC_(pIRowsetRefresh->GetLastVisibleData(phRows2[0], hAccessor2, pData),S_OK);
|
|
}
|
|
else
|
|
{
|
|
//refresh the data from the rowset
|
|
TESTC_(pIRowsetResynch->ResynchRows(1, &phRows2[0], &cRowsResynched, &rghReRows, &rgReRowStatus),S_OK);
|
|
TESTC_(pIRowsetResynch->GetVisibleData(phRows2[0], hAccessor2, pData),S_OK);
|
|
}
|
|
|
|
//Check this row against ulRowNum, free pData when done
|
|
if (CompareData(((CTable *)m_pThisTestModule->m_pVoid)->CountColumnsOnTable(), m_rgTableColOrds,
|
|
g_ulLastActualInsert+1, pData, cBindings, rgBindings,
|
|
((CTable *)m_pThisTestModule->m_pVoid), m_pIMalloc, PRIMARY,
|
|
COMPARE_FREE, COMPARE_UNTIL_ERROR))
|
|
{
|
|
//We found the row, woo-hoo., resynch works w/OTHERUPDATEDELETE - FALSE
|
|
fResult = TEST_PASS;
|
|
}
|
|
//Free the row for this GetNextRows call
|
|
TESTC_(pIRowset2->ReleaseRows(1, phRows2, NULL, NULL, NULL), S_OK);
|
|
CLEANUP:
|
|
//clean up any changes this little kludge messed on the back end
|
|
pITransactionLocal->Abort(NULL,FALSE,FALSE);
|
|
|
|
//Cleanup any out of line memory allocated in FillInputBindings and pData
|
|
ReleaseInputBindingsMemory(cBindings, rgBindings, pData, TRUE);
|
|
if (rgBindings)
|
|
{
|
|
PROVIDER_FREE(rgBindings);
|
|
}
|
|
|
|
//Release accessor1
|
|
if ((hAccessor1 != DB_NULL_HACCESSOR) && pIAccessor1)
|
|
{
|
|
CHECK(pIAccessor1->ReleaseAccessor(hAccessor1, NULL), S_OK);
|
|
hAccessor1 = DB_NULL_HACCESSOR;
|
|
}
|
|
//Release accessor2
|
|
if ((hAccessor2 != DB_NULL_HACCESSOR) && pIAccessor2)
|
|
{
|
|
CHECK(pIAccessor2->ReleaseAccessor(hAccessor2, NULL), S_OK);
|
|
hAccessor2 = DB_NULL_HACCESSOR;
|
|
}
|
|
|
|
PROVIDER_FREE(rgReRowStatus);
|
|
PROVIDER_FREE(rghReRows);
|
|
|
|
SAFE_RELEASE(pITransactionLocal);
|
|
SAFE_RELEASE(pIAccessor1);
|
|
SAFE_RELEASE(pIAccessor2);
|
|
SAFE_RELEASE(pIRowset1);
|
|
SAFE_RELEASE(pIRowset2);
|
|
SAFE_RELEASE(pIRowsetChange);
|
|
SAFE_RELEASE(pIRowsetRefresh);
|
|
SAFE_RELEASE(pIRowsetResynch);
|
|
|
|
return fResult;
|
|
}
|
|
// }}
|
|
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(4)
|
|
//--------------------------------------------------------------------
|
|
// @mfunc GetVisible twice w/BLOBs
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCMiscResynch::Variation_4()
|
|
{
|
|
HACCESSOR hAccessor1 = DB_NULL_HACCESSOR;
|
|
IAccessor *pIAccessor1 = NULL;
|
|
DBBINDING *rgBindings = NULL;
|
|
DBCOUNTITEM cBindings = 0;
|
|
ITransactionLocal *pITransactionLocal = NULL;
|
|
IRowsetChange *pIRowsetChange = NULL;
|
|
IRowsetRefresh *pIRowsetRefresh= NULL;
|
|
IRowsetResynch *pIRowsetResynch= NULL;
|
|
IRowset *pIRowset1 = NULL;
|
|
const ULONG cProps = 4;
|
|
DBPROPSET DBPropSet;
|
|
DBPROP DBProp[cProps];
|
|
HRESULT hr = S_OK;
|
|
BYTE *pData = NULL;
|
|
const ULONG cRows = 2;
|
|
HROW rghRows1[cRows];
|
|
HROW *phRows1 = rghRows1;
|
|
BOOL fResult = TEST_FAIL;
|
|
DBCOUNTITEM cRowsObtained = 1;
|
|
DBLENGTH cRowSize = 0;
|
|
DBCOUNTITEM cRowsResynched = 0;
|
|
ULONG i = 0;
|
|
|
|
|
|
//Struct for set properties
|
|
DBPropSet.guidPropertySet = DBPROPSET_ROWSET;
|
|
DBPropSet.rgProperties = DBProp;
|
|
DBPropSet.cProperties = cProps;
|
|
|
|
DBProp[0].dwPropertyID = DBPROP_IRowsetChange;
|
|
DBProp[0].dwOptions = DBPROPOPTIONS_REQUIRED;
|
|
DBProp[0].colid = DB_NULLID;
|
|
DBProp[0].vValue.vt = VT_BOOL;
|
|
V_BOOL(&(DBProp[0].vValue)) = VARIANT_TRUE;
|
|
|
|
DBProp[1].dwPropertyID = DBPROP_UPDATABILITY;
|
|
DBProp[1].dwOptions = 0;
|
|
DBProp[1].colid = DB_NULLID;
|
|
DBProp[1].vValue.vt = VT_I4;
|
|
DBProp[1].vValue.lVal = DBPROPVAL_UP_CHANGE | DBPROPVAL_UP_DELETE | DBPROPVAL_UP_INSERT;
|
|
|
|
if(g_fRefresh)
|
|
{
|
|
DBProp[2].dwPropertyID = DBPROP_IRowsetRefresh;
|
|
DBProp[2].dwOptions = 0;
|
|
DBProp[2].colid = DB_NULLID;
|
|
DBProp[2].vValue.vt = VT_BOOL;
|
|
V_BOOL(&(DBProp[2].vValue)) = VARIANT_TRUE;
|
|
}
|
|
else
|
|
{
|
|
DBProp[2].dwPropertyID = DBPROP_IRowsetResynch;
|
|
DBProp[2].dwOptions = 0;
|
|
DBProp[2].colid = DB_NULLID;
|
|
DBProp[2].vValue.vt = VT_BOOL;
|
|
V_BOOL(&(DBProp[2].vValue)) = VARIANT_TRUE;
|
|
}
|
|
|
|
DBProp[3].dwPropertyID = DBPROP_OTHERUPDATEDELETE;
|
|
DBProp[3].dwOptions = DBPROPOPTIONS_REQUIRED;
|
|
DBProp[3].colid = DB_NULLID;
|
|
DBProp[3].vValue.vt = VT_BOOL;
|
|
V_BOOL(&(DBProp[3].vValue)) = VARIANT_FALSE;
|
|
|
|
//Get IRowset on the object
|
|
if (!VerifyInterface((IUnknown *)m_pThisTestModule->m_pIUnknown2,
|
|
IID_ITransactionLocal, SESSION_INTERFACE, (IUnknown **)&pITransactionLocal))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
pITransactionLocal->StartTransaction(ISOLATIONLEVEL_READCOMMITTED, 0, NULL, NULL);
|
|
|
|
//get a rowsets
|
|
hr = ((CTable *)m_pThisTestModule->m_pVoid)->CreateRowset( USE_OPENROWSET,
|
|
IID_IRowset,
|
|
1,
|
|
&DBPropSet,
|
|
(IUnknown**)&pIRowset1,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
0,
|
|
NULL,
|
|
NULL);
|
|
|
|
//if IRowsetRefresh conflicts with DBPROP_OTHERUPDATEDELETE-FALSE skip this
|
|
if (hr != S_OK )
|
|
{
|
|
fResult = TEST_SKIPPED;
|
|
goto CLEANUP;
|
|
}
|
|
|
|
|
|
//Get accessor on the object
|
|
if (!VerifyInterface(pIRowset1, IID_IAccessor, ROWSET_INTERFACE, (IUnknown **)&pIAccessor1))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
|
|
TESTC_(GetAccessorAndBindings( pIAccessor1,
|
|
DBACCESSOR_ROWDATA,
|
|
&hAccessor1,
|
|
&rgBindings,
|
|
&cBindings,
|
|
&cRowSize,
|
|
DBPART_VALUE | DBPART_LENGTH | DBPART_STATUS,
|
|
ALL_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);
|
|
|
|
//Set data for all columns
|
|
TESTC_(FillInputBindings( ((CTable *)m_pThisTestModule->m_pVoid),
|
|
DBACCESSOR_ROWDATA,
|
|
cBindings,
|
|
rgBindings,
|
|
&pData,
|
|
g_ulLastActualInsert+1,
|
|
((CTable *)m_pThisTestModule->m_pVoid)->CountColumnsOnTable(),
|
|
m_rgTableColOrds), S_OK);
|
|
|
|
//Get IRowsetChange on the object
|
|
if (!VerifyInterface(pIRowset1, IID_IRowsetChange, ROWSET_INTERFACE, (IUnknown **)&pIRowsetChange))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
|
|
|
|
//get the first row through the 1st rowset
|
|
TESTC_(pIRowset1->RestartPosition(NULL), S_OK);
|
|
TESTC_(pIRowset1->GetNextRows(NULL, 0, 2, &cRowsObtained, &phRows1),S_OK);
|
|
|
|
if (g_fRefresh)
|
|
{
|
|
if (!VerifyInterface(pIRowset1, IID_IRowsetRefresh, ROWSET_INTERFACE, (IUnknown **)&pIRowsetRefresh))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
CHECK(pIRowsetRefresh->GetLastVisibleData(phRows1[0], hAccessor1, pData),S_OK);
|
|
CHECK(pIRowsetRefresh->GetLastVisibleData(phRows1[1], hAccessor1, pData),S_OK);
|
|
CHECK(pIRowset1->ReleaseRows(1, phRows1, NULL, NULL, NULL), S_OK);
|
|
CHECK(pIRowsetRefresh->GetLastVisibleData(phRows1[1], hAccessor1, pData),S_OK);
|
|
}
|
|
else
|
|
{
|
|
if (!VerifyInterface(pIRowset1, IID_IRowsetResynch, ROWSET_INTERFACE, (IUnknown **)&pIRowsetResynch))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
//BLOBS
|
|
CHECK(pIRowsetResynch->GetVisibleData(phRows1[0], hAccessor1, pData),DB_S_ERRORSOCCURRED);
|
|
for (i=0;i<cBindings;i++)
|
|
{
|
|
// if (DBSTATUS_E_UNAVAILABLE !=(*(DBSTATUS *)((DWORD)pData + rgBindings[i].obStatus)) &&
|
|
// DBSTATUS_S_OK !=(*(DBSTATUS *)((DWORD)pData + rgBindings[i].obStatus)))
|
|
if (
|
|
DBSTATUS_S_OK != STATUS_BINDING(rgBindings[i],pData) &&
|
|
DBSTATUS_E_UNAVAILABLE != STATUS_BINDING(rgBindings[i],pData)
|
|
)
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
}
|
|
|
|
//lets see this error again
|
|
CHECK(pIRowsetResynch->GetVisibleData(phRows1[1], hAccessor1, pData),DB_S_ERRORSOCCURRED);
|
|
}
|
|
fResult = TEST_PASS;
|
|
CLEANUP:
|
|
//clean up any changes this little kludge messed on the back end
|
|
pITransactionLocal->Abort(NULL,FALSE,FALSE);
|
|
|
|
//Cleanup any out of line memory allocated in FillInputBindings and pData
|
|
ReleaseInputBindingsMemory(cBindings, rgBindings, pData, TRUE);
|
|
if (rgBindings)
|
|
{
|
|
PROVIDER_FREE(rgBindings);
|
|
}
|
|
|
|
//Release accessor1
|
|
if ((hAccessor1 != DB_NULL_HACCESSOR) && pIAccessor1)
|
|
{
|
|
CHECK(pIAccessor1->ReleaseAccessor(hAccessor1, NULL), S_OK);
|
|
hAccessor1 = DB_NULL_HACCESSOR;
|
|
}
|
|
|
|
SAFE_RELEASE(pITransactionLocal);
|
|
SAFE_RELEASE(pIAccessor1);
|
|
SAFE_RELEASE(pIRowset1);
|
|
SAFE_RELEASE(pIRowsetChange);
|
|
SAFE_RELEASE(pIRowsetRefresh);
|
|
SAFE_RELEASE(pIRowsetResynch);
|
|
|
|
return fResult;
|
|
}
|
|
// }}
|
|
|
|
|
|
|
|
// {{ TCW_TERMINATE_METHOD
|
|
//--------------------------------------------------------------------
|
|
// @mfunc TestCase Termination Routine
|
|
//
|
|
// @rdesc TRUE or FALSE
|
|
//
|
|
BOOL TCMiscResynch::Terminate()
|
|
{
|
|
// {{ TCW_TERM_BASECLASS_CHECK2
|
|
return(CRowsetObject::Terminate());
|
|
} // }}
|
|
// }}
|
|
// }}
|