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