13582 lines
404 KiB
C++
13582 lines
404 KiB
C++
|
|
//--------------------------------------------------------------------
|
|
// Microsoft OLE DB Test
|
|
//
|
|
// Copyright 1995-2000 Microsoft Corporation.
|
|
//
|
|
// @doc
|
|
//
|
|
// @module IACCESSR.CPP | Test Module for IAccessor
|
|
//
|
|
//--------------------------------------------------------------------
|
|
|
|
#include "MODStandard.hpp"
|
|
|
|
#define DBINITCONSTANTS // Must be defined to initialize constants in oledb.h
|
|
#define INITGUID // For IID_ITransactionOptions, etc.
|
|
|
|
#include "iaccessr.h"
|
|
|
|
|
|
// At least one provider has a problem with row accessors created on commands
|
|
// This will help work around...
|
|
#define NO_COMMAND_ACCESSOR_HACK
|
|
|
|
#define SAFE_RELEASE_ACCESSOR(pIAcc, hAcc) {if ((pIAcc) && (hAcc) && \
|
|
CHECK((pIAcc)->ReleaseAccessor((hAcc), NULL), S_OK)) (hAcc) = DB_NULL_HACCESSOR;}
|
|
|
|
#define FREE_BINDINGS(x,y) {FreeAccessorBindings(*x,*y); *x = 0; *y = NULL;}
|
|
|
|
#define IS_BASE_TYPE(wType, wBaseType) (((wType) & ~(DBTYPE_ARRAY|DBTYPE_BYREF|DBTYPE_VECTOR)) == (wBaseType))
|
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Module Values
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// {{ TCW_MODULE_GLOBALS
|
|
DECLARE_MODULE_CLSID = { 0xabebd540, 0xfb6b, 0x11ce, { 0xa9, 0xe9, 0x00, 0xaa, 0x00, 0x3e, 0x77, 0x8a }};
|
|
DECLARE_MODULE_NAME("IAccessor");
|
|
DECLARE_MODULE_OWNER("Microsoft");
|
|
DECLARE_MODULE_DESCRIP("Test Module for IAccessor");
|
|
DECLARE_MODULE_VERSION(839294173);
|
|
// TCW_WizardVersion(2)
|
|
// TCW_Automation(True)
|
|
// }} TCW_MODULE_GLOBALS_END
|
|
|
|
//Indicate whether the provider is read only
|
|
BOOL g_fReadOnlyProvider = FALSE;
|
|
//Indicate whether the provider supports the parameter accessor
|
|
BOOL g_fParamAccessor= TRUE;
|
|
//Indicate whether the provider supports the command
|
|
BOOL g_fCmdSupported = TRUE;
|
|
//Flag to show output parameter support
|
|
BOOL g_fOutputParam;
|
|
//Row number used to create single row in table
|
|
UINT g_uiRowNum = 1;
|
|
//Use for creating parameter accessors, all we need is the ordinals in the order they appear in the accessor
|
|
const ULONG MAX_COLS = 25;
|
|
DBORDINAL g_rgParamOrds[MAX_COLS] = {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25};
|
|
|
|
//--------------------------------------------------------------------
|
|
// @func Module level initialization routine
|
|
//
|
|
// @rdesc Success or Failure
|
|
// @flag TRUE | Successful initialization
|
|
// @flag FALSE | Initialization problems
|
|
//
|
|
BOOL ModuleInit(CThisTestModule * pThisTestModule)
|
|
{
|
|
ULONG_PTR ulPropValue;
|
|
ULONG ulRowCount=0;
|
|
BOOL fNULLS=FALSE;
|
|
IOpenRowset * pIOpenRowset=NULL;
|
|
IDBCreateCommand * pIDBCreateCommand=NULL;
|
|
ICommandWithParameters * pICmdWPar=NULL;
|
|
|
|
if (ModuleCreateDBSession(pThisTestModule))
|
|
{
|
|
g_fParamAccessor = FALSE;
|
|
g_uiRowNum = 1;
|
|
|
|
// Check whether provider is read only
|
|
g_fReadOnlyProvider = IsProviderReadOnly((IUnknown *)pThisTestModule->m_pIUnknown2);
|
|
|
|
//Check whether the provider supports the parameter accessor by creating a command
|
|
// object and asking for ICommandWithParameters interface back.
|
|
pIOpenRowset=(IOpenRowset *)pThisTestModule->m_pIUnknown2;
|
|
if (VerifyInterface(pIOpenRowset, IID_IDBCreateCommand, SESSION_INTERFACE,
|
|
(IUnknown **)&pIDBCreateCommand))
|
|
{
|
|
// If we can get an ICommandWithParameters interface from a command object we must support
|
|
// parameter accessors
|
|
if (SUCCEEDED(pIDBCreateCommand->CreateCommand(NULL, IID_ICommandWithParameters, (IUnknown **)&pICmdWPar)))
|
|
g_fParamAccessor=TRUE;
|
|
|
|
SAFE_RELEASE(pICmdWPar);
|
|
SAFE_RELEASE(pIDBCreateCommand);
|
|
}
|
|
|
|
// See if output parameters are supported. We assume the lowest functionality if
|
|
// GetProperty fails as this property may not be supported.
|
|
g_fOutputParam = FALSE;
|
|
if (GetProperty(DBPROP_OUTPUTPARAMETERAVAILABILITY, DBPROPSET_DATASOURCEINFO,
|
|
(IUnknown *)pThisTestModule->m_pIUnknown, &ulPropValue) &&
|
|
ulPropValue != DBPROPVAL_OA_NOTSUPPORTED)
|
|
g_fOutputParam = TRUE;
|
|
|
|
//Create a table we'll use for the whole test module,
|
|
//store it in pVoid for now
|
|
pThisTestModule->m_pVoid = new CTable((IUnknown *)pThisTestModule->m_pIUnknown2,
|
|
(LPWSTR)gwszModuleName);
|
|
|
|
if (!pThisTestModule->m_pVoid)
|
|
{
|
|
odtLog << wszMemoryAllocationError;
|
|
return FALSE;
|
|
}
|
|
|
|
if(!((CTable *)pThisTestModule->m_pVoid)->GetCommandSupOnCTable() )
|
|
g_fCmdSupported = FALSE;
|
|
else
|
|
g_fCmdSupported = TRUE;
|
|
|
|
if (!CHECK(((CTable *)pThisTestModule->m_pVoid)->CreateTable(30), S_OK))
|
|
return FALSE;
|
|
|
|
// See if we're able to detect nulls in the table
|
|
if (((CTable *)pThisTestModule->m_pVoid)->GetNull() == NONULLS)
|
|
odtLog << L"Warning: This table doesn't claim to have NULL data values, so NULLs may not be tested.\n";
|
|
|
|
//If we made it this far, everything has succeeded
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
//--------------------------------------------------------------------
|
|
// @func Module level termination routine
|
|
//
|
|
// @rdesc Success or Failure
|
|
// @flag TRUE | Successful initialization
|
|
// @flag FALSE | Initialization problems
|
|
//
|
|
BOOL ModuleTerminate(CThisTestModule * pThisTestModule)
|
|
{
|
|
|
|
//We still own the table since all of our testcases
|
|
//have only used it and not deleted it.
|
|
if (pThisTestModule->m_pVoid)
|
|
{
|
|
if(g_fCmdSupported)
|
|
((CTable *)pThisTestModule->m_pVoid)->DropTable();
|
|
delete (CTable*)pThisTestModule->m_pVoid;
|
|
pThisTestModule->m_pVoid = NULL;
|
|
}
|
|
|
|
return ModuleReleaseDBSession(pThisTestModule);
|
|
}
|
|
|
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Base Class Section
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// @class CAccessor Base Class for all IAccessor Testcases
|
|
class CAccessor : public CRowsetObject
|
|
{
|
|
public:
|
|
// @cmember Constructor
|
|
CAccessor(LPWSTR wszTestCaseName);
|
|
// @cmember Destructor
|
|
~CAccessor(){};
|
|
|
|
|
|
protected:
|
|
// @cmember Common base class initialization
|
|
BOOL Init();
|
|
// @cmember Common base class termination
|
|
BOOL Terminate();
|
|
|
|
//@cmember Copies one binding's values to another
|
|
void CopyBindings(
|
|
DBBINDING * dbBindDest, //@parm [IN] Destination array
|
|
DBBINDING * dbBindSrc //@parm [IN] Sources
|
|
);
|
|
|
|
//@cmember If provider supports IRowsetLocate (ie, whether we can bind
|
|
//long data and get it back using ODBC Provider)
|
|
BLOBTYPE m_fBindLongCols;
|
|
|
|
//@cmember Cleans up a rowset object
|
|
void CleanUpRowsetObject(BOOL fReleaseAccessor = TRUE);
|
|
|
|
//@cmember Creates a rowset object and optionally calls GetNextRows and GetData
|
|
HRESULT OpenRowsetObject(BOOL fGetData = FALSE);
|
|
|
|
//@cmember Tries to GetNextRows and GetData with IRowset
|
|
HRESULT GetRowsAndData(IUnknown * pIUnknown, HACCESSOR hAccessor,
|
|
DBLENGTH cbRowSize, BYTE ** ppData=NULL, IRowset ** ppIRowset=NULL, HROW ** prghRows=NULL);
|
|
|
|
//@cmember Verifies return code from CreateAccessor call
|
|
BOOL VerifyError(
|
|
IUnknown * pIUnknown,
|
|
HACCESSOR hAccessor,
|
|
HRESULT ExpectedHr,
|
|
DBBINDSTATUS dbExpectedStatus,
|
|
LONG lStatusIndex,
|
|
DBBINDING * rgBinding,
|
|
enum DEFER_MODE eDeferMode,
|
|
enum FAILURE_MODE eFailMode = MUST_FAIL,
|
|
BOOL fCompareData=TRUE,
|
|
BYTE ** pDataBuf=NULL);
|
|
|
|
//@cmember Verifies that GetBindings returns the same binding array
|
|
//as was used to create the accessor
|
|
BOOL VerifyBindings(
|
|
IAccessor * pIAccessor, //@parm [IN] Interface to do GetBindings on
|
|
DBBINDING * rgCreateBindings, //@parm [IN] Array of bindings used to create accessor
|
|
DBCOUNTITEM cCreateBindings, //@parm [IN] Count of bindin structs in array
|
|
HACCESSOR hAccessor, //@parm [IN] Handle of accessor created, for which we'll do GetBindings
|
|
DBACCESSORFLAGS dwCreateAccessorFlags//@parm [IN] Value of Accessor flags used to create accessor
|
|
);
|
|
|
|
|
|
// @cmember Gets data with accessor and validates value, status and len were returned correctly
|
|
HRESULT UseRowAccessorAndVerify(
|
|
HACCESSOR hAccessor, //@parm [IN] Handle of accessor
|
|
DBLENGTH cbRowSize, //@parm [IN] Size of buffer needed for row
|
|
ULONG ulRowNum, //@parm [IN] Row number needed for MakeData
|
|
DB_LORDINAL * rgColumnsOrd, //@parm [IN] Back end ordinals corresponding to rowset cols
|
|
DBCOUNTITEM cColumns, //@parm [IN] Number of ordinals in rgColumnsOrd array
|
|
DBBINDING * rgBinding, //@parm [IN] Array of bindings for this accessor
|
|
DBCOUNTITEM cBinding, //@parm [IN] Number of bindings in rgBinding array
|
|
BOOL fReadColumnsByRef = FALSE, //@parm [IN] Whether or not accessor is READCOLUMNSBYREF
|
|
BOOL fKeepCurrentRows = FALSE); //@parm [IN] Specifies if rows are kept for next call or not
|
|
|
|
// @cmember Uses parameter accessor for input parameters on select statement,
|
|
// and verifies that the query result was correct
|
|
HRESULT UseParamAccessorAndVerify(
|
|
HACCESSOR hAccessor, //@parm [IN] Parameter accessor to use
|
|
DBACCESSORFLAGS dwAccessorFlags, //@parm [IN] Accessor flags
|
|
DBLENGTH cbRowSize, //@parm [IN] Size for one row of parameter data
|
|
ULONG ulRowNum, //@parm [IN] Row number needed for MakeData
|
|
DBBINDING * rgBinding, //@parm [IN] Array of bindings for this accessor
|
|
DBCOUNTITEM cBinding, //@parm [IN] Number of bindings in rgBinding array
|
|
ICommand * pICommand, //@parm [IN] Command to execute on. Must match accessor command object.
|
|
HRESULT hrExecute=S_OK, //@parm [IN] Expected hresult from Execute call.
|
|
BOOL fWarn = FALSE);
|
|
|
|
//@cmember Find a set of types that satisfy required conversion needs
|
|
BOOL FindConversionTypes(
|
|
DBBINDING * prgBindings,
|
|
DBCOUNTITEM cBindings,
|
|
ULONG * piBackEnd,
|
|
DBTYPE * wOptType,
|
|
DBTYPE * wNonOptType);
|
|
|
|
// @cmember Utility function to set all bindings to the given parameter type
|
|
void SetParamIO(DBCOUNTITEM cBindings, DBBINDING * rgBindings, DBPARAMIO eParamIO);
|
|
|
|
//@cmember Changes bindings to the specified memory owner for
|
|
//all the types for which dwMemOwner applies
|
|
void AdjustMemOwner(DBMEMOWNERENUM eMemOwner, DBCOUNTITEM cBindings, DBBINDING * rgBindings);
|
|
|
|
//@cmember Accept success but print failure for log if not S_OK on non-ReadOnly provider
|
|
BOOL CheckHr(HRESULT hr);
|
|
|
|
//@cmember Verifies required properties are set on rowset
|
|
HRESULT VerifyRowsetProperties(IUnknown * pIUnknown, DBPROPSET * rgPropertySets, ULONG cPropertySets);
|
|
|
|
//@cmember Check for provider support of binding fixed length columns BYREF
|
|
enum FIXED_BYREF_SUPPORT SupportFixedByRef(IUnknown * pIUnknown);
|
|
|
|
//@cmember Flag indicating whether or not pass by ref accessors are supported
|
|
BOOL m_fPassByRef;
|
|
|
|
//@cmember Array of status for each binding
|
|
DBBINDSTATUS * m_rgStatus;
|
|
|
|
//@cmember Count of bindings in m_rgBindings
|
|
DBCOUNTITEM m_cBindings;
|
|
|
|
//@cmember Count of bindings in m_rgBindings2
|
|
DBCOUNTITEM m_cBindings2;
|
|
|
|
//@cmember Array of DBBINDINGS used to create an accessor
|
|
DBBINDING * m_rgBindings;
|
|
|
|
//@cmember Array of DBBINDINGS used to create a second accessor
|
|
DBBINDING * m_rgBindings2;
|
|
|
|
//@cmember Row size used to allocate buffer pointed to by m_pData
|
|
DBLENGTH m_cbRowSize;
|
|
|
|
//@cmember Row size used to allocate buffer pointed to by m_pData2
|
|
DBLENGTH m_cbRowSize2;
|
|
|
|
//@cmember Number of binding which is in error
|
|
ULONG m_ulErrorBinding;
|
|
|
|
//@cmember Array of DBINDINGS retrieved via GetBindings
|
|
DBBINDING * m_rgGetBindings;
|
|
|
|
//@cmember Handle to created a accessor
|
|
HACCESSOR m_hAccessor;
|
|
|
|
//@cmember Handle to created a second accessor
|
|
HACCESSOR m_hAccessor2;
|
|
|
|
//@cmember Pointer to consumer's buffer
|
|
BYTE * m_pData;
|
|
|
|
//@cmember Pointer to consumer's second data buffer
|
|
BYTE * m_pData2;
|
|
|
|
//@cmember Count of columns in table
|
|
DBCOUNTITEM m_cTableColumns;
|
|
|
|
//@cmember Count of rows obtained from GetNextRows
|
|
DBCOUNTITEM m_cRowsObtained;
|
|
|
|
//@cmember Row handle retrieved from GetNextRows
|
|
HROW m_hRow;
|
|
|
|
//@cmember Interface pointer
|
|
IRowsetChange* m_pIRowsetChange;
|
|
|
|
//@cmember Interface pointer
|
|
IRowset * m_pIRowset;
|
|
|
|
//@cmember IAccessor on Command object
|
|
IAccessor * m_pCmdIAccessor;
|
|
|
|
//@cmember Flag indicating if IRowset is supported
|
|
BOOL m_fIRowset;
|
|
|
|
//@cmember Flag indicating if MAYREFERENCE is not set for any Fixed length columns
|
|
//BOOL m_fMayNotReferenceFixed;
|
|
|
|
//@cmember Flag indicating if MAYREFERENCE is not set for any Variable length columns
|
|
//BOOL m_fMayNotReferenceVariable;
|
|
|
|
//@cmember Count of searchable columns in rowset, used for parameterized queries
|
|
ULONG m_cSearchableCols;
|
|
|
|
//@cmember Array of ordinals of searchable columns in rowset, used for parameterized queries
|
|
DB_LORDINAL * m_rgSearchableCols;
|
|
|
|
//@cmember Property set for this test case
|
|
DBPROPSET * m_pDBPropSetLocate;
|
|
|
|
//@cmember Properties for this test case
|
|
DBPROP * m_prgDBPropsLocate;
|
|
|
|
//@cmember Storage object used for DBTYPE_IUNKNOWN bindings
|
|
DBOBJECT m_StorageObject;
|
|
|
|
//@cmember Flag to indicate provider supports OLE objects (IUNKNOWN).
|
|
BOOL m_fOLEOBJECTS;
|
|
|
|
};
|
|
|
|
|
|
//--------------------------------------------------------------------
|
|
// @mfunc Constructor
|
|
//
|
|
CAccessor::CAccessor(LPWSTR wszTestCaseName) : CRowsetObject(wszTestCaseName)
|
|
{
|
|
m_ulErrorBinding = 0;
|
|
m_hAccessor = DB_NULL_HACCESSOR;
|
|
m_hAccessor2 = DB_NULL_HACCESSOR;
|
|
m_fIRowset = FALSE;
|
|
m_cRowsObtained = 0;
|
|
m_cBindings = 0;
|
|
m_cBindings2 = 0;
|
|
m_rgBindings = NULL;
|
|
m_rgBindings2 = NULL;
|
|
m_pData = NULL;
|
|
m_pData2 = NULL;
|
|
m_cbRowSize = 1;
|
|
m_cbRowSize2 = 1;
|
|
m_rgGetBindings = NULL;
|
|
m_cTableColumns = 0;
|
|
m_pIRowsetChange = NULL;
|
|
m_pIRowset = NULL;
|
|
m_hRow = DB_NULL_HROW;
|
|
m_pCmdIAccessor = NULL;
|
|
m_cSearchableCols = 0;
|
|
m_rgSearchableCols = NULL;
|
|
m_rgStatus = NULL;
|
|
m_fPassByRef = FALSE;
|
|
m_pDBPropSetLocate = NULL;
|
|
m_prgDBPropsLocate = NULL;
|
|
m_fOLEOBJECTS = FALSE;
|
|
m_StorageObject.dwFlags=STGM_READ;
|
|
m_StorageObject.iid=IID_ISequentialStream;
|
|
}
|
|
|
|
//--------------------------------------------------------------------
|
|
// @mfunc Base class Initialization Routine
|
|
//
|
|
// @rdesc TRUE or FALSE
|
|
//
|
|
BOOL CAccessor::Init()
|
|
{
|
|
IDBProperties * pIDBProp = NULL;
|
|
DBPROPIDSET PropIDSet;
|
|
PROPID PropID = DBPROP_BYREFACCESSORS;
|
|
ULONG cPropSets = 0;
|
|
DBPROPSET * rgPropSets = NULL;
|
|
ICommandProperties * pICmdProps = NULL;
|
|
HRESULT hr;
|
|
ULONG_PTR ulPropValue=0;
|
|
|
|
// Check for OLE object support
|
|
if (GetProperty(DBPROP_OLEOBJECTS, DBPROPSET_DATASOURCEINFO,
|
|
(IUnknown *)m_pThisTestModule->m_pIUnknown, &ulPropValue) &&
|
|
ulPropValue & DBPROPVAL_OO_BLOB)
|
|
m_fOLEOBJECTS=TRUE;
|
|
|
|
if (m_fOLEOBJECTS)
|
|
{
|
|
// Find out what storage object is needed
|
|
if (COMPARE(GetProperty(DBPROP_STRUCTUREDSTORAGE, DBPROPSET_DATASOURCEINFO,
|
|
(IUnknown *)m_pThisTestModule->m_pIUnknown, &ulPropValue),TRUE))
|
|
{
|
|
if (ulPropValue & DBPROPVAL_SS_ISEQUENTIALSTREAM)
|
|
m_StorageObject.iid=IID_ISequentialStream;
|
|
else if (ulPropValue & DBPROPVAL_SS_ISTREAM)
|
|
m_StorageObject.iid=IID_IStream;
|
|
else if (ulPropValue & DBPROPVAL_SS_ISTORAGE)
|
|
m_StorageObject.iid=IID_IStorage;
|
|
else if (ulPropValue & DBPROPVAL_SS_ILOCKBYTES)
|
|
m_StorageObject.iid=IID_ILockBytes;
|
|
else
|
|
{
|
|
// This is an error,
|
|
odtLog << L"OLE Objects supported but no valid structured storage type was returned.\n";
|
|
COMPARE(1, 0);
|
|
m_fOLEOBJECTS = FALSE;
|
|
}
|
|
}
|
|
else
|
|
// We couldn't retrieve the storage type required, drop back to no support
|
|
m_fOLEOBJECTS = FALSE;
|
|
}
|
|
|
|
// Initialize storage object flag member
|
|
m_StorageObject.dwFlags=STGM_READ;
|
|
|
|
m_pDBPropSetLocate = (DBPROPSET *)PROVIDER_ALLOC(sizeof(DBPROPSET));
|
|
m_prgDBPropsLocate = (DBPROP *)PROVIDER_ALLOC(sizeof(DBPROP));
|
|
|
|
if (!m_pDBPropSetLocate || !m_prgDBPropsLocate)
|
|
{
|
|
odtLog << wszMemoryAllocationError;
|
|
return FALSE;
|
|
}
|
|
|
|
//Prop structs for setting IRowsetLocate
|
|
m_pDBPropSetLocate->guidPropertySet = DBPROPSET_ROWSET;
|
|
m_pDBPropSetLocate->rgProperties = m_prgDBPropsLocate;
|
|
m_pDBPropSetLocate->cProperties = 1;
|
|
m_prgDBPropsLocate[0].dwPropertyID = DBPROP_IRowsetLocate;
|
|
//Note this is required because otherwise ODBC Provider won't
|
|
//consider it cheap and we will lose long data testing
|
|
m_prgDBPropsLocate[0].dwOptions = DBPROPOPTIONS_REQUIRED;
|
|
m_prgDBPropsLocate[0].colid = DB_NULLID;
|
|
m_prgDBPropsLocate[0].vValue.vt = VT_BOOL;
|
|
V_BOOL(&m_prgDBPropsLocate[0].vValue) = VARIANT_TRUE;
|
|
|
|
//Prop struct for asking about BYREFACCESSOR support
|
|
PropIDSet.guidPropertySet = DBPROPSET_DATASOURCEINFO;
|
|
PropIDSet.cPropertyIDs = 1;
|
|
PropIDSet.rgPropertyIDs = &PropID;
|
|
|
|
if(CRowsetObject::Init())
|
|
{
|
|
//Copy the IDBCreateCommand pointer we got at the
|
|
//module level down to the testcase level.
|
|
//Note, this increments the ref count, so we call
|
|
//ReleaseDBSession in the Terminate, but the DBSession
|
|
//does not go away until ModuleTerminate time
|
|
SetDBSession((IDBCreateCommand *)m_pThisTestModule->m_pIUnknown2);
|
|
|
|
//Have this testcase use the table created in ModuleInit, but don't
|
|
//let table be deleted, since we'll use it for next test case
|
|
SetTable((CTable *)m_pThisTestModule->m_pVoid, DELETETABLE_NO);
|
|
|
|
//Record number of columns in the table
|
|
m_cTableColumns = m_pTable->CountColumnsOnTable();
|
|
|
|
//Zero is returned if there was an error counting columns
|
|
if (!m_cTableColumns)
|
|
return FALSE;
|
|
|
|
//Allocate the max array we'll need for binding status
|
|
//We add one to col total since we may have bookmarks
|
|
m_rgStatus = (DBBINDSTATUS *)m_pIMalloc->Alloc((m_cTableColumns+1) * sizeof(DBBINDSTATUS));
|
|
if (!m_rgStatus)
|
|
return FALSE;
|
|
|
|
//Find out if PASS BY REF Accessors are supported
|
|
if (VerifyInterface((IDBInitialize *)m_pThisTestModule->m_pIUnknown, IID_IDBProperties, DATASOURCE_INTERFACE,
|
|
(IUnknown **)&pIDBProp))
|
|
{
|
|
HRESULT hrGetProp = E_FAIL;
|
|
|
|
hrGetProp = pIDBProp->GetProperties(1, &PropIDSet, &cPropSets, &rgPropSets);
|
|
|
|
// Since we only asked for one prop we must only get one back
|
|
if (hrGetProp == S_OK || hrGetProp == DB_E_ERRORSOCCURRED)
|
|
{
|
|
if (COMPARE(cPropSets, 1) && COMPARE(rgPropSets[0].cProperties, 1))
|
|
{
|
|
if (hrGetProp == S_OK)
|
|
{
|
|
// There is only one set with one property
|
|
COMPARE(rgPropSets[0].rgProperties[0].dwStatus, DBPROPSTATUS_OK);
|
|
m_fPassByRef = (VARIANT_TRUE == rgPropSets[0].rgProperties[0].vValue.boolVal);
|
|
}
|
|
else if (hrGetProp == DB_E_ERRORSOCCURRED)
|
|
{
|
|
//The only other acceptable value is not supported
|
|
COMPARE(rgPropSets[0].rgProperties[0].dwStatus, DBPROPSTATUS_NOTSUPPORTED);
|
|
m_fPassByRef = FALSE;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
CHECK(hrGetProp, S_OK);
|
|
|
|
//release property sets
|
|
FreeProperties(&cPropSets, &rgPropSets);
|
|
SAFE_RELEASE(pIDBProp);
|
|
}
|
|
|
|
//Find out if IRowsetLocate is supported
|
|
SetRowsetProperties(m_pDBPropSetLocate, 1);
|
|
|
|
if (SUCCEEDED(hr=CreateRowsetObject(SELECT_VALIDATIONORDER)))
|
|
{
|
|
|
|
//Record our ability to bind long columns
|
|
//NOTE: This is only a restriction for ODBC Provider,
|
|
//other providers may be able to bind long data
|
|
//without the support of IRowsetLocate
|
|
|
|
//We assume we have only one property set, so
|
|
//we'll access the zeroth element of m_rgPropSets
|
|
COMPARE(m_cPropSets, 1);
|
|
// if (m_rgPropSets[0].rgProperties[0].dwStatus == DBPROPSTATUS_OK)
|
|
m_fBindLongCols = BLOB_LONG;
|
|
// else
|
|
// m_fBindLongCols = NO_BLOB_COLS;
|
|
|
|
//Keep command so that IRowsetLocate property is always set
|
|
//for all rowsets generated. It is SETIFCHEAP, so if it
|
|
//is not supported, we will still work.
|
|
ReleaseRowsetObject();
|
|
return TRUE;
|
|
}
|
|
else if(hr==DB_E_ERRORSOCCURRED)
|
|
{
|
|
m_fBindLongCols = NO_BLOB_COLS;
|
|
|
|
// Release the properties which will affect opening rowset later
|
|
if (m_rgPropSets)
|
|
{
|
|
// Walk Set array, freeing all member property arrays
|
|
for(ULONG i=0; i<m_cPropSets; i++)
|
|
{
|
|
PROVIDER_FREE(m_rgPropSets[i].rgProperties);
|
|
}
|
|
|
|
PROVIDER_FREE(m_rgPropSets);
|
|
m_cPropSets = 0;
|
|
}
|
|
return TRUE;
|
|
}
|
|
}
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
//--------------------------------------------------------------------
|
|
// @mfunc Base Case Termination Routine
|
|
//
|
|
// @rdesc TRUE or FALSE
|
|
//
|
|
BOOL CAccessor::Terminate()
|
|
{
|
|
// Make sure we don't leak the binding information
|
|
CleanUpRowsetObject();
|
|
|
|
//Cleanup as much as we allocated in the base class init
|
|
ReleaseCommandObject();
|
|
ReleaseDBSession();
|
|
|
|
// Free property array
|
|
PROVIDER_FREE(m_pDBPropSetLocate);
|
|
PROVIDER_FREE(m_prgDBPropsLocate);
|
|
|
|
//Free binding status array
|
|
PROVIDER_FREE(m_rgStatus);
|
|
|
|
return(CRowsetObject::Terminate());
|
|
}
|
|
|
|
//--------------------------------------------------------------------
|
|
// @mfunc Cleans up member vars associated with rowset object
|
|
//
|
|
void CAccessor::CleanUpRowsetObject(BOOL fReleaseAccessor)
|
|
{
|
|
// We might have bindings already, don't overwrite
|
|
FREE_BINDINGS(&m_cBindings, &m_rgBindings);
|
|
|
|
// Reset to 0 and NULL
|
|
m_cBindings = 0;
|
|
m_rgBindings = NULL;
|
|
|
|
if (fReleaseAccessor)
|
|
{
|
|
// We might have created an accessor; we don't want to overwrite.
|
|
// Don't check return code because we don't know if the accessor was created on the command
|
|
// or rowset object.
|
|
if (m_pCmdIAccessor && m_hAccessor != DB_NULL_HACCESSOR &&
|
|
S_OK == m_pCmdIAccessor->ReleaseAccessor(m_hAccessor, NULL))
|
|
m_hAccessor = DB_NULL_HACCESSOR;
|
|
if (m_pIAccessor && m_hAccessor != DB_NULL_HACCESSOR &&
|
|
S_OK == m_pIAccessor->ReleaseAccessor(m_hAccessor, NULL))
|
|
m_hAccessor = DB_NULL_HACCESSOR;
|
|
}
|
|
|
|
SAFE_RELEASE(m_pCmdIAccessor);
|
|
SAFE_RELEASE(m_pIRowset);
|
|
|
|
// Release the rowset in case it exists. Note this releases m_pIAccessor for us.
|
|
ReleaseRowsetObject();
|
|
|
|
m_fIRowset = FALSE;
|
|
}
|
|
|
|
//--------------------------------------------------------------------
|
|
// @mfunc Creates a rowset object and optionally calls GetNextRows and GetData
|
|
//
|
|
HRESULT CAccessor::OpenRowsetObject(BOOL fGetData)
|
|
{
|
|
IRowsetInfo * pIRowsetInfo = NULL;
|
|
HACCESSOR hAccessor = DB_NULL_HACCESSOR;
|
|
HRESULT hr = E_FAIL;
|
|
|
|
CleanUpRowsetObject(FALSE);
|
|
|
|
//Set m_pIAccessor on a 'select *' rowset We'll
|
|
//use this interface ptr to do our tests.
|
|
|
|
hr=CreateRowsetObject(SELECT_VALIDATIONORDER);
|
|
|
|
#ifdef COMMAND_ACCESSOR_HACK
|
|
// Hack for Service Components
|
|
if (!CHECK(hr, S_OK))
|
|
{
|
|
SAFE_RELEASE(m_pICommand);
|
|
TESTC_(m_pIDBCreateCommand->CreateCommand(NULL, IID_ICommand, (IUnknown **)&m_pICommand), S_OK);
|
|
hr=CreateRowsetObject(SELECT_VALIDATIONORDER);
|
|
}
|
|
#endif
|
|
|
|
TESTC_(hr, S_OK);
|
|
|
|
TESTC(m_pIAccessor != NULL);
|
|
|
|
// Get a rowset interface for later use
|
|
TESTC(VerifyInterface(m_pIAccessor, IID_IRowset, ROWSET_INTERFACE,
|
|
(IUnknown **)&m_pIRowset));
|
|
|
|
m_fIRowset = TRUE;
|
|
|
|
//Now get a command if that is applicable
|
|
TESTC(VerifyInterface(m_pIAccessor, IID_IRowsetInfo, ROWSET_INTERFACE,
|
|
(IUnknown **)&pIRowsetInfo));
|
|
|
|
if(g_fCmdSupported)
|
|
{
|
|
//Note that NULL is put in m_pCmdIAccesor if that fails, which is what
|
|
//we'll do the check on to determine support
|
|
hr = pIRowsetInfo->GetSpecification(IID_IAccessor, (IUnknown **)&m_pCmdIAccessor);
|
|
|
|
// Some providers may return S_FALSE from GetSpecification
|
|
if (S_FALSE == hr)
|
|
{
|
|
if (m_pICommand && !VerifyInterface(m_pICommand, IID_IAccessor, COMMAND_INTERFACE,
|
|
(IUnknown **)&m_pCmdIAccessor))
|
|
g_fCmdSupported = FALSE;
|
|
}
|
|
else
|
|
TESTC_(hr, S_OK);
|
|
}
|
|
|
|
//Fill in m_rgBindings, m_cBindings and m_cbRowSize with valid values
|
|
TESTC_(GetAccessorAndBindings(m_pIAccessor, DBACCESSOR_ROWDATA,
|
|
&hAccessor, &m_rgBindings, &m_cBindings, &m_cbRowSize,
|
|
DBPART_VALUE | DBPART_LENGTH | DBPART_STATUS,
|
|
ALL_COLS_BOUND,
|
|
FORWARD, NO_COLS_BY_REF, NULL, NULL,
|
|
NULL, DBTYPE_EMPTY, 0, NULL, NULL,
|
|
NO_COLS_OWNED_BY_PROV, DBPARAMIO_NOTPARAM,
|
|
m_fBindLongCols),S_OK);
|
|
|
|
//Get Rows to force immediate validation,
|
|
//we need a valid m_hAccessor for this call
|
|
if (fGetData)
|
|
TESTC_(GetRowsAndData(m_pIAccessor, hAccessor, m_cbRowSize), S_OK);
|
|
|
|
// We'll just use the bindings after this, so release accessor
|
|
// Don't consider this a fatal error if it fails
|
|
if (CHECK(m_pIAccessor->ReleaseAccessor(hAccessor, NULL), S_OK))
|
|
hAccessor = DB_NULL_HACCESSOR;
|
|
|
|
hr = S_OK;
|
|
|
|
CLEANUP:
|
|
|
|
SAFE_RELEASE(pIRowsetInfo);
|
|
|
|
// Release the rowset object on error
|
|
if (S_OK != hr)
|
|
{
|
|
SAFE_RELEASE(m_pCmdIAccessor);
|
|
SAFE_RELEASE(m_pIRowset);
|
|
ReleaseRowsetObject();
|
|
m_fIRowset = FALSE;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
//--------------------------------------------------------------------
|
|
// @mfunc Accept success but print failure for log if not S_OK on
|
|
// non-ReadOnly provider
|
|
//
|
|
BOOL CAccessor::CheckHr(HRESULT hr)
|
|
{
|
|
// We want to accept DB_S_ERRORSOCCURRED if it is returned, but
|
|
// we should print a failure for the log. S_OK is the expected result for
|
|
// non-ReadOnly providers.
|
|
if (!g_fReadOnlyProvider)
|
|
CHECK(hr, S_OK);
|
|
return SUCCEEDED(hr);
|
|
}
|
|
|
|
|
|
//--------------------------------------------------------------------
|
|
// @mfunc Copies bindings from dbBindSrc to dbBindDest
|
|
//
|
|
void CAccessor::CopyBindings(DBBINDING * dbBindDest, DBBINDING * dbBindSrc)
|
|
{
|
|
ASSERT(dbBindDest);
|
|
ASSERT(dbBindSrc);
|
|
|
|
|
|
dbBindDest->iOrdinal = dbBindSrc->iOrdinal;
|
|
dbBindDest->dwPart = dbBindSrc->dwPart;
|
|
dbBindDest->wType = dbBindSrc->wType;
|
|
dbBindDest->eParamIO = dbBindSrc->eParamIO;
|
|
dbBindDest->pTypeInfo = dbBindSrc->pTypeInfo;
|
|
dbBindDest->obValue = dbBindSrc->obValue;
|
|
dbBindDest->cbMaxLen = dbBindSrc->cbMaxLen;
|
|
if (dbBindSrc->pObject)
|
|
{
|
|
//Allocate a new object for the destination binding
|
|
dbBindDest->pObject = (DBOBJECT *)m_pIMalloc->Alloc(sizeof(DBOBJECT));
|
|
dbBindDest->pObject->dwFlags = dbBindSrc->pObject->dwFlags;
|
|
dbBindDest->pObject->iid = dbBindSrc->pObject->iid;
|
|
}
|
|
else
|
|
dbBindDest->pObject = NULL;
|
|
dbBindDest->obLength = dbBindSrc->obLength;
|
|
dbBindDest->obStatus = dbBindSrc->obStatus;
|
|
dbBindDest->dwMemOwner = dbBindSrc->dwMemOwner;
|
|
dbBindDest->pBindExt = dbBindSrc->pBindExt;
|
|
dbBindDest->dwFlags = dbBindSrc->dwFlags;
|
|
dbBindDest->bPrecision = dbBindSrc->bPrecision;
|
|
dbBindDest->bScale = dbBindSrc->bScale;
|
|
|
|
|
|
}
|
|
|
|
//--------------------------------------------------------------------
|
|
// @mfunc Utility function to set each binding to eParamIO
|
|
//
|
|
void CAccessor::SetParamIO(DBCOUNTITEM cBindings, DBBINDING * rgBindings, DBPARAMIO eParamIO)
|
|
{
|
|
while (cBindings)
|
|
{
|
|
rgBindings[cBindings-1].eParamIO = eParamIO;
|
|
cBindings--;
|
|
}
|
|
}
|
|
//--------------------------------------------------------------------
|
|
// @mfunc Gets IRowset, calls GetNextRows and GetData on it.
|
|
//
|
|
HRESULT CAccessor::GetRowsAndData(IUnknown * pIUnknown, HACCESSOR hAccessor,
|
|
DBLENGTH cbRowSize, BYTE ** ppData, IRowset ** ppIRowset, HROW ** pprghRows)
|
|
{
|
|
IRowset * pIRowset = NULL;
|
|
DBCOUNTITEM cRowsObtained = 0;
|
|
BYTE * pData = NULL;
|
|
HROW * prghRows = NULL;
|
|
|
|
//Alloc enough for a row buffer
|
|
pData = (BYTE *)m_pIMalloc->Alloc(cbRowSize);
|
|
if (!pData)
|
|
return ResultFromScode(E_OUTOFMEMORY);
|
|
|
|
//Get an IRowset interface
|
|
if (VerifyInterface(pIUnknown,IID_IRowset,ROWSET_INTERFACE,(IUnknown **)&pIRowset))
|
|
{
|
|
//We could get a couple of different S codes for the next two calls
|
|
m_pError->SetErrorLevel(HR_SUCCEED);
|
|
|
|
//Start at beginning of rowset
|
|
CHECK(pIRowset->RestartPosition(NULL), S_OK);
|
|
|
|
//Fetch one row of data
|
|
CHECK(m_hr = pIRowset->GetNextRows(NULL,0,1,&cRowsObtained, &prghRows), IGNORE);
|
|
m_pError->SetErrorLevel(HR_STRICT);
|
|
|
|
//In case we get DB_S_ENDOFROWSET, need to also check cRowsObtained
|
|
if (SUCCEEDED(m_hr) && cRowsObtained)
|
|
m_hr = pIRowset->GetData(*prghRows, hAccessor, pData);
|
|
|
|
if (prghRows)
|
|
{
|
|
if (pprghRows)
|
|
*pprghRows = prghRows;
|
|
else
|
|
{
|
|
pIRowset->ReleaseRows(1, prghRows, NULL, NULL, NULL);
|
|
PROVIDER_FREE(prghRows);
|
|
}
|
|
}
|
|
|
|
}
|
|
else
|
|
m_hr = E_FAIL;
|
|
|
|
if (pData)
|
|
{
|
|
//Either give memory to user
|
|
if (ppData)
|
|
*ppData = pData;
|
|
else
|
|
{
|
|
// Or release it. Unfortunately for BYREF types we have to know the bindings to release the memory.
|
|
// We could pass in the bindings, but it's better to exercise GetBindings...
|
|
if (pIRowset)
|
|
{
|
|
IAccessor * pIAccessor = NULL;
|
|
DBCOUNTITEM cBindings;
|
|
DBACCESSORFLAGS dwAccessorFlags;
|
|
DBBINDING * pBindings = NULL;
|
|
|
|
if (!VerifyInterface(pIRowset, IID_IAccessor, ROWSET_INTERFACE, (IUnknown **)&pIAccessor))
|
|
m_hr = E_FAIL;
|
|
|
|
CHECK(pIAccessor->GetBindings(hAccessor, &dwAccessorFlags, &cBindings, &pBindings), S_OK);
|
|
|
|
CHECK(ReleaseInputBindingsMemory(cBindings, pBindings, pData, TRUE), S_OK);
|
|
|
|
CHECK(FreeAccessorBindings(cBindings, pBindings), S_OK);
|
|
|
|
SAFE_RELEASE(pIAccessor);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (ppIRowset)
|
|
*ppIRowset = pIRowset;
|
|
else
|
|
SAFE_RELEASE(pIRowset);
|
|
|
|
//Return GetNextRows or GetData Result
|
|
return m_hr;
|
|
|
|
}
|
|
|
|
//--------------------------------------------------------------------
|
|
// @mfunc Verifies GetBindings returns the same bindings array
|
|
// as was used to create the accessor
|
|
//
|
|
// @rdesc TRUE or FALSE
|
|
// @flag TRUE The Bindings match
|
|
// @flag FALSE The Bindings do not match
|
|
//
|
|
BOOL CAccessor::VerifyBindings(
|
|
IAccessor * pIAccessor, //@parm [IN] Interface to do GetBindings on
|
|
DBBINDING * rgCreateBindings, //@parm [IN] Array of bindings used to create accessor
|
|
DBCOUNTITEM cCreateBindings, //@parm [IN] Count of bindin structs in array
|
|
HACCESSOR hAccessor, //@parm [IN] Handle of accessor created, for which we'll do GetBindings
|
|
DBACCESSORFLAGS dwCreateAccessorFlags)//@parm [IN] Value of Accessor flags used to create accessor
|
|
|
|
{
|
|
DBACCESSORFLAGS dwGetAccessorFlags = 0;
|
|
DBCOUNTITEM cGetBindings = 0;
|
|
ULONG i;
|
|
DBBINDING * rgGetBindings = NULL;
|
|
HRESULT hr = E_FAIL;
|
|
|
|
ASSERT(pIAccessor);
|
|
|
|
hr = pIAccessor->GetBindings(hAccessor, &dwGetAccessorFlags,
|
|
&cGetBindings, &rgGetBindings);
|
|
|
|
TESTC_(hr, S_OK);
|
|
|
|
// Some providers just ignore the DBACCESSOR_OPTIMIZED bit because an optimized accessor
|
|
// is identical to a regular accessor, therefore the bit may not be returned even if set. Providers are allowed
|
|
// to not return this bit in GetBindings, so make this a warning.
|
|
if (dwCreateAccessorFlags & DBACCESSOR_OPTIMIZED && !(dwGetAccessorFlags & DBACCESSOR_OPTIMIZED))
|
|
{
|
|
odtLog << L"DBACCESSOR_OPTIMIZED bit not returned from GetBindings.\n";
|
|
TESTW(dwCreateAccessorFlags == dwGetAccessorFlags);
|
|
dwCreateAccessorFlags &= ~DBACCESSOR_OPTIMIZED;
|
|
}
|
|
|
|
TESTC(dwGetAccessorFlags == dwCreateAccessorFlags);
|
|
TESTC(cGetBindings == cCreateBindings);
|
|
|
|
//Set up index for bindings
|
|
if (cGetBindings == 0)
|
|
{
|
|
//This is a null accessor, binding array should be null
|
|
TESTC(rgGetBindings == NULL);
|
|
}
|
|
else
|
|
{
|
|
for (i=0; i < cGetBindings; i++)
|
|
{
|
|
// iOrdinal
|
|
TESTC(rgGetBindings[i].iOrdinal == rgCreateBindings[i].iOrdinal);
|
|
|
|
// obValue
|
|
if (rgCreateBindings[i].dwPart & DBPART_VALUE)
|
|
{
|
|
TESTC(rgGetBindings[i].obValue == rgCreateBindings[i].obValue);
|
|
}
|
|
|
|
// obLength
|
|
if (rgCreateBindings[i].dwPart & DBPART_LENGTH)
|
|
{
|
|
TESTC(rgGetBindings[i].obLength == rgCreateBindings[i].obLength);
|
|
}
|
|
|
|
// obStatus
|
|
if (rgCreateBindings[i].dwPart & DBPART_STATUS)
|
|
{
|
|
TESTC(rgGetBindings[i].obStatus == rgCreateBindings[i].obStatus);
|
|
}
|
|
|
|
// pTypeInfo
|
|
TESTC(rgGetBindings[i].pTypeInfo == rgCreateBindings[i].pTypeInfo);
|
|
|
|
// pObject. Only applies if VALUE bound and type is DBTYPE_UNKNOWN
|
|
if (rgCreateBindings[i].dwPart & DBPART_VALUE &&
|
|
rgCreateBindings[i].wType == DBTYPE_IUNKNOWN)
|
|
{
|
|
TESTC(rgGetBindings[i].pObject->dwFlags == rgCreateBindings[i].pObject->dwFlags);
|
|
TESTC(rgGetBindings[i].pObject->iid == rgCreateBindings[i].pObject->iid);
|
|
}
|
|
|
|
// pBindExt
|
|
TESTC(rgGetBindings[i].pBindExt == rgCreateBindings[i].pBindExt);
|
|
|
|
// dwPart
|
|
TESTC(rgGetBindings[i].dwPart == rgCreateBindings[i].dwPart);
|
|
|
|
// dwMemOwner
|
|
TESTC(rgGetBindings[i].dwMemOwner == rgCreateBindings[i].dwMemOwner);
|
|
|
|
// eParamIO
|
|
TESTC(rgGetBindings[i].eParamIO == rgCreateBindings[i].eParamIO);
|
|
|
|
// cbMaxLen
|
|
if (rgCreateBindings[i].dwPart & DBPART_VALUE)
|
|
{
|
|
TESTC(rgGetBindings[i].cbMaxLen == rgCreateBindings[i].cbMaxLen);
|
|
}
|
|
|
|
// dwFlags: Only valid for string types
|
|
// Providers that don't support DBBINDFLAG_HTML will likely not return it,
|
|
// so don't fail them for that.
|
|
if (IS_BASE_TYPE(rgCreateBindings[i].wType, DBTYPE_STR) ||
|
|
IS_BASE_TYPE(rgCreateBindings[i].wType, DBTYPE_WSTR))
|
|
{
|
|
|
|
if (rgCreateBindings[i].dwFlags & DBBINDFLAG_HTML)
|
|
{
|
|
// Warning if flag not set
|
|
COMPAREW(!!(rgGetBindings[i].dwFlags & DBBINDFLAG_HTML), TRUE);
|
|
|
|
// Remove the flag from each binding
|
|
rgGetBindings[i].dwFlags &= ~DBBINDFLAG_HTML;
|
|
rgCreateBindings[i].dwFlags &= ~DBBINDFLAG_HTML;
|
|
|
|
}
|
|
TESTC(rgGetBindings[i].dwFlags == rgCreateBindings[i].dwFlags);
|
|
}
|
|
|
|
//Precision and scale only apply for numeric and decimal types
|
|
//and then only if VALUE is bound
|
|
if ((rgCreateBindings[i].wType == DBTYPE_NUMERIC ||
|
|
rgCreateBindings[i].wType == DBTYPE_DECIMAL) &&
|
|
(rgCreateBindings[i].dwPart & DBPART_VALUE))
|
|
{
|
|
TESTC(rgGetBindings[i].bPrecision == rgCreateBindings[i].bPrecision);
|
|
TESTC(rgGetBindings[i].bScale == rgCreateBindings[i].bScale);
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
|
|
PROVIDER_FREE(rgGetBindings);
|
|
|
|
//If we get here, we must have passed
|
|
return TRUE;
|
|
|
|
|
|
CLEANUP:
|
|
PROVIDER_FREE(rgGetBindings);
|
|
return FALSE;
|
|
|
|
|
|
}
|
|
|
|
// Verify error returned from CreateAccessor call.
|
|
BOOL CAccessor::VerifyError(
|
|
IUnknown * pIUnknown,
|
|
HACCESSOR hAccessor,
|
|
HRESULT ExpectedHr,
|
|
DBBINDSTATUS dbExpectedStatus,
|
|
LONG lStatusIndex,
|
|
DBBINDING * rgBinding,
|
|
enum DEFER_MODE eDeferMode,
|
|
enum FAILURE_MODE eFailMode,
|
|
BOOL fCompareData,
|
|
BYTE ** pDataBuf)
|
|
{
|
|
BOOL fResults = FALSE;
|
|
BYTE * pData = NULL;
|
|
IRowset * pIRowset = NULL;
|
|
HROW * prghRows = NULL;
|
|
|
|
ASSERT (eDeferMode == IMMEDIATE ||
|
|
eDeferMode == MAY_DEFERR ||
|
|
eDeferMode == MUST_DEFERR);
|
|
|
|
|
|
if ((eDeferMode == IMMEDIATE && eFailMode == MUST_FAIL) ||
|
|
(eDeferMode == IMMEDIATE && eFailMode == MAY_FAIL && FAILED(m_hr)) ||
|
|
(eDeferMode == MAY_DEFERR && FAILED(m_hr)))
|
|
{
|
|
//CreateAccessor must always return DB_E_ERRORSOCCURRED in immediate mode
|
|
|
|
//Verify correct binding is identified as bad and accessor
|
|
//is nulled, in addition to the return code being correct
|
|
fResults = CHECK(m_hr, DB_E_ERRORSOCCURRED) &&
|
|
((lStatusIndex != -1) ? COMPARE(dbExpectedStatus, m_rgStatus[lStatusIndex]) : TRUE) &&
|
|
COMPARE(NULL, hAccessor);
|
|
}
|
|
else
|
|
{
|
|
//If validation is deferred, the CreateAccessor call must have succeeded
|
|
if (CHECK(m_hr, NOERROR))
|
|
{
|
|
//But using the accessor should fail
|
|
m_hr = GetRowsAndData(pIUnknown, hAccessor, m_cbRowSize, &pData, &pIRowset, &prghRows);
|
|
|
|
// If we failed here but specified immediate mode then the provider has a bug,
|
|
// For a MAY_FAIL case we should succeed here in IMMEDIATE mode.
|
|
if (eDeferMode == IMMEDIATE && eFailMode == MAY_FAIL && FAILED(m_hr))
|
|
CHECK(m_hr, S_OK);
|
|
//This can be either DB_S_ERRORSOCCURRED
|
|
else if (m_hr == DB_S_ERRORSOCCURRED || m_hr == DB_E_ERRORSOCCURRED)
|
|
{
|
|
//Then the status must be right for the correct binding
|
|
fResults = COMPARE(STATUS_BINDING(rgBinding[lStatusIndex], pData), DBSTATUS_E_BADACCESSOR);
|
|
|
|
//Further, if we return DB_E_ERRORSOCCURED, we must have done
|
|
//no useful work, therefore it must be the first binding that failed
|
|
if (m_hr == DB_E_ERRORSOCCURRED)
|
|
fResults &= COMPARE(lStatusIndex, 0);
|
|
}
|
|
//Or we can fail outright
|
|
else if (eFailMode == MUST_FAIL || !SUCCEEDED(m_hr))
|
|
fResults = CHECK(m_hr, ExpectedHr);
|
|
else
|
|
fResults = CHECK(m_hr, S_OK);
|
|
|
|
// If we got back data then we didn't get an error. This may be valid in
|
|
// some cases (MAY_FAIL cases).
|
|
if (fCompareData && SUCCEEDED(m_hr) &&
|
|
STATUS_BINDING(rgBinding[lStatusIndex], pData) == DBSTATUS_S_OK)
|
|
{
|
|
|
|
// If we got data back then GetData succeeded
|
|
// Make sure it matches what we expect
|
|
fResults &= COMPARE(CompareData(
|
|
m_cRowsetCols,
|
|
m_rgTableColOrds,
|
|
1,
|
|
pData,
|
|
1,
|
|
&rgBinding[lStatusIndex],
|
|
m_pTable,
|
|
m_pIMalloc,
|
|
PRIMARY,
|
|
(pDataBuf) ? COMPARE_ONLY : COMPARE_FREE,
|
|
COMPARE_ALL,
|
|
TRUE
|
|
), TRUE);
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
|
|
if (pDataBuf)
|
|
*pDataBuf = pData;
|
|
else
|
|
PROVIDER_FREE(pData);
|
|
|
|
// Release any rows obtained in GetRowsAndData. Should be 1 row handle.
|
|
if (pIRowset && prghRows)
|
|
{
|
|
pIRowset->ReleaseRows(1, prghRows, NULL, NULL, NULL);
|
|
PROVIDER_FREE(prghRows);
|
|
}
|
|
SAFE_RELEASE(pIRowset);
|
|
|
|
return fResults;
|
|
}
|
|
|
|
void CAccessor::AdjustMemOwner(DBMEMOWNERENUM eMemOwner, DBCOUNTITEM cBindings, DBBINDING * rgBindings)
|
|
{
|
|
ULONG i;
|
|
for (i=0; i<cBindings; i++)
|
|
{
|
|
//Only change dwMemOwner if the type is appropriate
|
|
|
|
if (rgBindings[i].wType & DBTYPE_BYREF ||
|
|
rgBindings[i].wType & DBTYPE_VECTOR ||
|
|
rgBindings[i].wType & DBTYPE_ARRAY ||
|
|
//Strip off a possible BYREF to check if its a BSTR
|
|
(~(DBTYPE_BYREF) & rgBindings[i].wType) == DBTYPE_BSTR)
|
|
{
|
|
//Switch to type of memory owner caller wants
|
|
if (eMemOwner == DBMEMOWNER_PROVIDEROWNED)
|
|
rgBindings[i].dwMemOwner = DBMEMOWNER_PROVIDEROWNED;
|
|
else
|
|
rgBindings[i].dwMemOwner = DBMEMOWNER_CLIENTOWNED;
|
|
}
|
|
}
|
|
}
|
|
|
|
HRESULT CAccessor::VerifyRowsetProperties(IUnknown * pIUnknown, DBPROPSET * rgPropertySets, ULONG cPropertySets)
|
|
{
|
|
// We opened a rowset, but we need to make sure the properties we need are set
|
|
IRowsetInfo * pIRowsetInfo = NULL;
|
|
HRESULT hr = S_OK;
|
|
ULONG iPropSet, iProp;
|
|
VARIANT vPropertyVal;
|
|
|
|
if (VerifyInterface(pIUnknown, IID_IRowsetInfo, ROWSET_INTERFACE, (IUnknown **)&pIRowsetInfo))
|
|
{
|
|
for (iPropSet = 0; iPropSet < cPropertySets; iPropSet++)
|
|
{
|
|
for (iProp = 0; iProp < rgPropertySets[iPropSet].cProperties; iProp++)
|
|
{
|
|
if (rgPropertySets[iPropSet].rgProperties[iProp].dwOptions == DBPROPOPTIONS_REQUIRED)
|
|
{
|
|
VariantInit(&vPropertyVal);
|
|
|
|
// This is a required property, verify it is set on the rowset
|
|
if (!GetProperty(
|
|
rgPropertySets[iPropSet].rgProperties[iProp].dwPropertyID,
|
|
rgPropertySets[iPropSet].guidPropertySet,
|
|
(IUnknown *)pIRowsetInfo,
|
|
&vPropertyVal))
|
|
{
|
|
// Couldn't read the property
|
|
hr = E_FAIL;
|
|
goto CLEANUP;
|
|
}
|
|
|
|
if (rgPropertySets[iPropSet].guidPropertySet == DBPROPSET_ROWSET &&
|
|
rgPropertySets[iPropSet].rgProperties[iProp].dwPropertyID == DBPROP_UPDATABILITY)
|
|
{
|
|
// This is a bitmask property, just make sure the bits we asked for are set
|
|
// Currently there is only one bitmask property
|
|
if (V_I4(&rgPropertySets[iPropSet].rgProperties[iProp].vValue) !=
|
|
(V_I4(&vPropertyVal) &
|
|
V_I4(&rgPropertySets[iPropSet].rgProperties[iProp].vValue)))
|
|
// if (Rowset & Asked != Asked) then the bits (properties) we
|
|
// needed on the rowset were not there.
|
|
{
|
|
hr = E_FAIL;
|
|
goto CLEANUP;
|
|
}
|
|
}
|
|
else
|
|
// Compare values exactly
|
|
if (!CompareVariant(
|
|
&rgPropertySets[iPropSet].rgProperties[iProp].vValue,
|
|
&vPropertyVal))
|
|
{
|
|
// Variants don't match
|
|
hr = E_FAIL;
|
|
goto CLEANUP;
|
|
}
|
|
|
|
|
|
VariantClear(&vPropertyVal);
|
|
|
|
}
|
|
|
|
} // Next property
|
|
|
|
} // Next property set
|
|
|
|
}
|
|
else
|
|
// Couldn't get the IRowsetInfo interface
|
|
hr = E_FAIL;
|
|
|
|
CLEANUP:
|
|
|
|
SAFE_RELEASE(pIRowsetInfo);
|
|
|
|
VariantClear(&vPropertyVal);
|
|
|
|
if (!SUCCEEDED(hr))
|
|
odtLog << L"Requested properties not supported.\n";
|
|
|
|
return hr;
|
|
}
|
|
|
|
// Note: Due to the spec issue noted below this function will report FIXED_BYREF_SOME or
|
|
// FIXED_BYREF_ALL for tables that contain fixed length binary or char columns.
|
|
enum FIXED_BYREF_SUPPORT CAccessor::SupportFixedByRef(IUnknown * pIUnknown)
|
|
{
|
|
IConvertType * pIConvertType=NULL;
|
|
IColumnsInfo * pIColumnsInfo = NULL;
|
|
CCol TempCol;
|
|
enum FIXED_BYREF_SUPPORT eSupport = FIXED_BYREF_ALL;
|
|
ULONG cFixedColsByRef = 0;
|
|
DBTYPE wFromType, wToType;
|
|
HRESULT hr;
|
|
DBORDINAL cColumns;
|
|
DBCOLUMNINFO * pColInfo=NULL;
|
|
WCHAR * pStringsBuffer=NULL;
|
|
|
|
// We need to obtain an IConvertType interface first
|
|
if(!VerifyInterface(pIUnknown,IID_IConvertType, ROWSET_INTERFACE,
|
|
(IUnknown **)&pIConvertType))
|
|
return FIXED_BYREF_NONE;
|
|
|
|
// We also need IColumnsInfo
|
|
if(!VerifyInterface(pIUnknown,IID_IColumnsInfo, ROWSET_INTERFACE,
|
|
(IUnknown **)&pIColumnsInfo))
|
|
return FIXED_BYREF_NONE;
|
|
|
|
// Get column information
|
|
if (!CHECK(pIColumnsInfo->GetColumnInfo(&cColumns, &pColInfo, &pStringsBuffer), S_OK))
|
|
return FIXED_BYREF_NONE;
|
|
|
|
// Go through all the columns of the table to verify fixed length BYREF bind support.
|
|
for (DBORDINAL iCol=0; iCol<cColumns; iCol++)
|
|
{
|
|
// If this is a fixed length column
|
|
if(pColInfo[iCol].dwFlags & DBCOLUMNFLAGS_ISFIXEDLENGTH)
|
|
{
|
|
// See if we support BYREF conversion
|
|
wFromType = pColInfo[iCol].wType;
|
|
|
|
// We always bind natively except for bookmarks which are always bound to DBTYPE_BYTES
|
|
wToType = wFromType;
|
|
if (!pColInfo[iCol].iOrdinal)
|
|
wToType = DBTYPE_BYTES;
|
|
|
|
hr = pIConvertType->CanConvert(wFromType, wToType|DBTYPE_BYREF, DBCONVERTFLAGS_COLUMN);
|
|
|
|
if (S_OK == hr)
|
|
cFixedColsByRef++;
|
|
else if (S_FALSE == hr)
|
|
eSupport = FIXED_BYREF_SOME;
|
|
else
|
|
CHECK(hr, S_OK);
|
|
}
|
|
|
|
}
|
|
|
|
if (!cFixedColsByRef)
|
|
eSupport = FIXED_BYREF_NONE;
|
|
|
|
// Currently we have no providers that support some fixed cols by ref. Test
|
|
// will need updating if this occurs
|
|
|
|
// Note: there's currently a spec issue where CanConvert will return S_OK for fixed length
|
|
// binary or char columns even though at this time no providers actually support this conversion.
|
|
// Currently CanConvert doesn't know anything about fixed vs. variable length conversions.
|
|
if (eSupport == FIXED_BYREF_SOME)
|
|
odtLog << L"Please update this test to support SOME fixed length columns bound BYREF.\n";
|
|
|
|
SAFE_RELEASE(pIConvertType);
|
|
SAFE_RELEASE(pIColumnsInfo);
|
|
PROVIDER_FREE(pColInfo);
|
|
PROVIDER_FREE(pStringsBuffer);
|
|
|
|
return eSupport;
|
|
|
|
}
|
|
|
|
//Dummy class only defined so that CRowsetObject can
|
|
//be instantiated as an object without inheriting
|
|
//from a real testcase
|
|
class CSetRowsetObject : public CRowsetObject
|
|
{
|
|
public:
|
|
|
|
//@cmember CTOR
|
|
CSetRowsetObject(LPWSTR tcName, CThisTestModule *pMod, ICommand * pICommand = NULL,
|
|
CTable * pTable = NULL):CRowsetObject(tcName)
|
|
{
|
|
ASSERT(pMod);
|
|
SetOwningMod(0, pMod);
|
|
if (pICommand)
|
|
SetCommandObject(pICommand);
|
|
m_pTable = pTable;
|
|
};
|
|
|
|
~CSetRowsetObject()
|
|
{
|
|
// m_pICommand is NULLed by the CCommand constructor in the base class, so
|
|
// it will only be non-NULL if we passed a pointer in the constructor
|
|
SAFE_RELEASE(m_pICommand); // Because SetCommandObject addrefed it.
|
|
}
|
|
|
|
};
|
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Test Case Section
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
|
|
|
|
// {{ TCW_TEST_CASE_MAP(TCCrtRtnValsAfterGetRows)
|
|
//--------------------------------------------------------------------
|
|
// @class Return values for all CreateAccessor error conditions
|
|
//
|
|
class TCCrtRtnValsAfterGetRows : public CAccessor {
|
|
private:
|
|
// @cmember Static array of variations
|
|
DECLARE_TEST_CASE_DATA();
|
|
|
|
public:
|
|
// {{ TCW_DECLARE_FUNCS
|
|
// @cmember Execution Routine
|
|
DECLARE_TEST_CASE_FUNCS(TCCrtRtnValsAfterGetRows,CAccessor);
|
|
// }} TCW_DECLARE_FUNCS_END
|
|
|
|
// @cmember Initialization Routine
|
|
virtual BOOL Init();
|
|
// @cmember Termination Routine
|
|
virtual BOOL Terminate();
|
|
|
|
// {{ TCW_TESTVARS()
|
|
// @cmember E_INVALIDARG - Null phAccessor
|
|
int Variation_1();
|
|
// @cmember DB_E_BADBINDINFO - Invalid dwPart
|
|
int Variation_2();
|
|
// @cmember DB_E_BADBINDINFO - wType is DBTYPE_EMPTY
|
|
int Variation_3();
|
|
// @cmember DB_E_BADBINDINFO - PASSBYREF without correct buffer format
|
|
int Variation_4();
|
|
// @cmember DB_E_BADBINDINFO - DBMEMOWNER_PROVIDEROWNED with DBTYPE not matching provider's
|
|
int Variation_5();
|
|
// @cmember DB_E_BADBINDINFO - PARAMETERDATA and Multiple Input bindings with same ordinal
|
|
int Variation_6();
|
|
// @cmember DB_E_BADACCESSORFLAGS - PASSBYREF when DBPROP_BYREFACCESSORS is FALSE
|
|
int Variation_7();
|
|
// @cmember DB_E_BADBINDINFO - PARAMETERDATA with invalid eParamIO
|
|
int Variation_8();
|
|
// @cmember DB_E_BADACCESSORFLAGS - OPTIMIZED created after GetNextRows
|
|
int Variation_9();
|
|
// @cmember DB_E_BADBINDINFO - Second optimized accessor using same column
|
|
int Variation_10();
|
|
// @cmember DB_E_BADBINDINFO - Accessor with invalid coersion for column in existing optimized accessor
|
|
int Variation_11();
|
|
// @cmember DB_E_BADORDINAL - iOrdinal of largest column number + 1
|
|
int Variation_12();
|
|
// @cmember DB_E_BADORDINAL - iOrdinal of max value for ULONG
|
|
int Variation_13();
|
|
// @cmember DB_E_BADBINDINFO - DBTYPE_BYREF with DBTYPE_EMPTY
|
|
int Variation_14();
|
|
// @cmember DB_E_BADBINDINFO - DBTYPE_BYREF with DBTYPE_NULL
|
|
int Variation_15();
|
|
// @cmember DB_E_BADBINDINFO - DBTYPE_BYREF with DBTYPE_RESERVED
|
|
int Variation_16();
|
|
// @cmember DB_E_BADBINDINFO - DBTYPE_ARRAY | DBTYPE_BYREF
|
|
int Variation_17();
|
|
// @cmember DB_E_BADBINDINFO - DBTYPE_ARRAY | DBTYPE_VECTOR
|
|
int Variation_18();
|
|
// @cmember DB_E_BADBINDINFO - DBTYPE_VECTOR | DBTYPE_BYREF
|
|
int Variation_19();
|
|
// @cmember S_OK - PASSBYREF and DBMEMOWNER_PROVIDEROWNED
|
|
int Variation_20();
|
|
// @cmember DB_E_BADACCESSORFLAGS - Invalid DBACCESSORFLAGS
|
|
int Variation_21();
|
|
// @cmember DB_E_BADORDINAL - iOrdinal = 0 for PARAMETERDATA accessor
|
|
int Variation_22();
|
|
// @cmember DB_E_BADORDINAL - iOrdinal = 0 for ROWDATA accessor without bookmarks
|
|
int Variation_23();
|
|
// @cmember DB_E_BADBINDINFO - DBMEMOWNER_PROVIDEROWNED with PARAMETERDATA
|
|
int Variation_24();
|
|
// @cmember S_OK - PARAMETERDATA and Multiple OUTPUT bindings with same ordinal
|
|
int Variation_25();
|
|
// @cmember DB_E_BADBINDINFO - wType is DBTYPE_NULL
|
|
int Variation_26();
|
|
// @cmember E_INVALID - cBindings != 0 and rgBindings = NULL
|
|
int Variation_27();
|
|
// @cmember DB_E_BADACCESSORFLAGS - dwAccessorFlags = OPTIMIZED only
|
|
int Variation_28();
|
|
// @cmember DB_E_BADACCESSORFLAGS - dwAccessorFlags = INVALID only
|
|
int Variation_29();
|
|
// @cmember DB_E_NULLACCESSORNOTSUPPORTED - Null accessor created on Command Object
|
|
int Variation_30();
|
|
// @cmember PARAMETERDATA accessor on Rowset Object
|
|
int Variation_31();
|
|
// @cmember DB_E_ERRORSOCCURRED - PROVIDEROWNED dwMemOwner for non pointer types
|
|
int Variation_32();
|
|
// @cmember DB_E_BADBINDINFO - DBTYPE_IUnknown and NULL pObject
|
|
int Variation_33();
|
|
// @cmember DB_E_BADBINDINFO: DBBINDFLAG_HTML for non-string type
|
|
int Variation_34();
|
|
// @cmember DB_E_BADBINDINFO: dwFlags invalid
|
|
int Variation_35();
|
|
// @cmember DB_E_NULLACCESSORNOTSUPPORTED - Null accessor on rowset with IRowsetChange FALSE
|
|
int Variation_36();
|
|
// @cmember DB_E_BADBINDINFO: dwMemOwner invalid
|
|
int Variation_37();
|
|
// }} TCW_TESTVARS_END
|
|
|
|
//@cmember Does CreateAccessor with a command rowdata accessor, expecting
|
|
//the given binding to have the given status
|
|
HRESULT TestCommandAccessor(DBBINDSTATUS status, LONG lBinding, enum DEFER_MODE eDeferMode,
|
|
DBACCESSORFLAGS dwAccessorFlags);
|
|
};
|
|
// {{ TCW_TESTCASE(TCCrtRtnValsAfterGetRows)
|
|
#define THE_CLASS TCCrtRtnValsAfterGetRows
|
|
BEG_TEST_CASE(TCCrtRtnValsAfterGetRows, CAccessor, L"Return values for all CreateAccessor error conditions")
|
|
TEST_VARIATION(1, L"E_INVALIDARG - Null phAccessor")
|
|
TEST_VARIATION(2, L"DB_E_BADBINDINFO - Invalid dwPart")
|
|
TEST_VARIATION(3, L"DB_E_BADBINDINFO - wType is DBTYPE_EMPTY")
|
|
TEST_VARIATION(4, L"DB_E_BADBINDINFO - PASSBYREF without correct buffer format")
|
|
TEST_VARIATION(5, L"DB_E_BADBINDINFO - DBMEMOWNER_PROVIDEROWNED with DBTYPE not matching provider's")
|
|
TEST_VARIATION(6, L"DB_E_BADBINDINFO - PARAMETERDATA and Multiple Input bindings with same ordinal")
|
|
TEST_VARIATION(7, L"DB_E_BADACCESSORFLAGS - PASSBYREF when DBPROP_BYREFACCESSORS is FALSE")
|
|
TEST_VARIATION(8, L"DB_E_BADBINDINFO - PARAMETERDATA with invalid eParamIO")
|
|
TEST_VARIATION(9, L"DB_E_BADACCESSORFLAGS - OPTIMIZED created after GetNextRows")
|
|
TEST_VARIATION(10, L"DB_E_BADBINDINFO - Second optimized accessor using same column")
|
|
TEST_VARIATION(11, L"DB_E_BADBINDINFO - Accessor with invalid coersion for column in existing optimized accessor")
|
|
TEST_VARIATION(12, L"DB_E_BADORDINAL - iOrdinal of largest column number + 1")
|
|
TEST_VARIATION(13, L"DB_E_BADORDINAL - iOrdinal of max value for ULONG")
|
|
TEST_VARIATION(14, L"DB_E_BADBINDINFO - DBTYPE_BYREF with DBTYPE_EMPTY")
|
|
TEST_VARIATION(15, L"DB_E_BADBINDINFO - DBTYPE_BYREF with DBTYPE_NULL")
|
|
TEST_VARIATION(16, L"DB_E_BADBINDINFO - DBTYPE_BYREF with DBTYPE_RESERVED")
|
|
TEST_VARIATION(17, L"DB_E_BADBINDINFO - DBTYPE_ARRAY | DBTYPE_BYREF")
|
|
TEST_VARIATION(18, L"DB_E_BADBINDINFO - DBTYPE_ARRAY | DBTYPE_VECTOR")
|
|
TEST_VARIATION(19, L"DB_E_BADBINDINFO - DBTYPE_VECTOR | DBTYPE_BYREF")
|
|
TEST_VARIATION(20, L"S_OK - PASSBYREF and DBMEMOWNER_PROVIDEROWNED")
|
|
TEST_VARIATION(21, L"DB_E_BADACCESSORFLAGS - Invalid DBACCESSORFLAGS")
|
|
TEST_VARIATION(22, L"DB_E_BADORDINAL - iOrdinal = 0 for PARAMETERDATA accessor")
|
|
TEST_VARIATION(23, L"DB_E_BADORDINAL - iOrdinal = 0 for ROWDATA accessor without bookmarks")
|
|
TEST_VARIATION(24, L"DB_E_BADBINDINFO - DBMEMOWNER_PROVIDEROWNED with PARAMETERDATA")
|
|
TEST_VARIATION(25, L"S_OK - PARAMETERDATA and Multiple OUTPUT bindings with same ordinal")
|
|
TEST_VARIATION(26, L"DB_E_BADBINDINFO - wType is DBTYPE_NULL")
|
|
TEST_VARIATION(27, L"E_INVALID - cBindings != 0 and rgBindings = NULL")
|
|
TEST_VARIATION(28, L"DB_E_BADACCESSORFLAGS - dwAccessorFlags = OPTIMIZED only")
|
|
TEST_VARIATION(29, L"DB_E_BADACCESSORFLAGS - dwAccessorFlags = INVALID only")
|
|
TEST_VARIATION(30, L"DB_E_NULLACCESSORNOTSUPPORTED - Null accessor created on Command Object")
|
|
TEST_VARIATION(31, L"PARAMETERDATA accessor on Rowset Object")
|
|
TEST_VARIATION(32, L"DB_E_ERRORSOCCURRED - PROVIDEROWNED dwMemOwner for non pointer types")
|
|
TEST_VARIATION(33, L"DB_E_BADBINDINFO - DBTYPE_IUnknown and NULL pObject")
|
|
TEST_VARIATION(34, L"DB_E_BADBINDINFO: DBBINDFLAG_HTML for non-string type")
|
|
TEST_VARIATION(35, L"DB_E_BADBINDINFO: dwFlags invalid")
|
|
TEST_VARIATION(36, L"DB_E_NULLACCESSORNOTSUPPORTED - Null accessor on rowset with IRowsetChange FALSE")
|
|
TEST_VARIATION(37, L"DB_E_BADBINDINFO: dwMemOwner invalid")
|
|
END_TEST_CASE()
|
|
#undef THE_CLASS
|
|
// }} TCW_TESTCASE_END
|
|
// }} TCW_TEST_CASE_MAP_END
|
|
|
|
|
|
// {{ TCW_TEST_CASE_MAP(TCCreateValidRowAccessors)
|
|
//--------------------------------------------------------------------
|
|
// @class Creation of valid row accessors
|
|
//
|
|
class TCCreateValidRowAccessors : public CAccessor {
|
|
private:
|
|
// @cmember Static array of variations
|
|
DECLARE_TEST_CASE_DATA();
|
|
|
|
DBPROPSET * m_pDBPropSet;
|
|
DBPROP * m_prgDBProps;
|
|
|
|
|
|
public:
|
|
// {{ TCW_DECLARE_FUNCS
|
|
// @cmember Execution Routine
|
|
DECLARE_TEST_CASE_FUNCS(TCCreateValidRowAccessors,CAccessor);
|
|
// }} TCW_DECLARE_FUNCS_END
|
|
|
|
//check whether the DBPROP_IRowsetChange and DBPROP_UPDATABILITY
|
|
BOOL m_fPropertiesSet;
|
|
|
|
// @cmember Initialization Routine
|
|
virtual BOOL Init();
|
|
// @cmember Termination Routine
|
|
virtual BOOL Terminate();
|
|
|
|
|
|
// {{ TCW_TESTVARS()
|
|
// @cmember Null Accessor
|
|
int Variation_1();
|
|
// @cmember dwPart = DBPART_VALUE
|
|
int Variation_2();
|
|
// @cmember dwPart = DBPART_LENGTH
|
|
int Variation_3();
|
|
// @cmember dwPart = DBPART_STATUS
|
|
int Variation_4();
|
|
// @cmember dwPart = DBCOLUMPART_LENGTH | DBCOLUMPART_STATUS
|
|
int Variation_5();
|
|
// @cmember dwPart = DBCOLUMPART_LENGTH | DBCOLUMPART_STATUS | DBCOLUMPART_VALUE
|
|
int Variation_6();
|
|
// @cmember One optmized, one non optimized, using same fields
|
|
int Variation_7();
|
|
// @cmember One non-optimized, one optimized, using same fields - different creation sequence
|
|
int Variation_8();
|
|
// @cmember One optimized, one non-optimized, using different fields
|
|
int Variation_9();
|
|
// @cmember Two optimized, using different fields
|
|
int Variation_10();
|
|
// @cmember Two non-optimized, using same fields
|
|
int Variation_11();
|
|
// @cmember Multiple bindings for same column in one accessor
|
|
int Variation_12();
|
|
// @cmember All types bound BY_REF, without DBMEMOWNER_PROVIDEROWNED
|
|
int Variation_13();
|
|
// @cmember Fixed types bound BY_REF, without DBMEMOWNER_PROVIDEROWNED
|
|
int Variation_14();
|
|
// @cmember Variable types bound BY_REF, without DBMEMOWNER_PROVIDEROWNED
|
|
int Variation_15();
|
|
// @cmember All types bound BY_REF, with DBMEMOWNER_PROVIDEROWNED
|
|
int Variation_16();
|
|
// @cmember Fixed types bound BY_REF, with DBMEMOWNER_PROVIDEROWNED
|
|
int Variation_17();
|
|
// @cmember Variable types bound BY_REF, with DBMEMOWNER_PROVIDEROWNED
|
|
int Variation_18();
|
|
// @cmember No types bound BY_REF, with DBMEMOWNER_PROVIDEROWNED
|
|
int Variation_19();
|
|
// @cmember Use accessor after release rows
|
|
int Variation_20();
|
|
// @cmember dwFlags: DBBINDFLAG_HTML
|
|
int Variation_21();
|
|
// @cmember DBACCESSOR_INHERITED - Or'd with DBACCESSOR_OPTIMIZED
|
|
int Variation_22();
|
|
// }} TCW_TESTVARS_END
|
|
};
|
|
// {{ TCW_TESTCASE(TCCreateValidRowAccessors)
|
|
#define THE_CLASS TCCreateValidRowAccessors
|
|
BEG_TEST_CASE(TCCreateValidRowAccessors, CAccessor, L"Creation of valid row accessors")
|
|
TEST_VARIATION(1, L"Null Accessor")
|
|
TEST_VARIATION(2, L"dwPart = DBPART_VALUE")
|
|
TEST_VARIATION(3, L"dwPart = DBPART_LENGTH")
|
|
TEST_VARIATION(4, L"dwPart = DBPART_STATUS")
|
|
TEST_VARIATION(5, L"dwPart = DBCOLUMPART_LENGTH | DBCOLUMPART_STATUS")
|
|
TEST_VARIATION(6, L"dwPart = DBCOLUMPART_LENGTH | DBCOLUMPART_STATUS | DBCOLUMPART_VALUE")
|
|
TEST_VARIATION(7, L"One optmized, one non optimized, using same fields")
|
|
TEST_VARIATION(8, L"One non-optimized, one optimized, using same fields - different creation sequence")
|
|
TEST_VARIATION(9, L"One optimized, one non-optimized, using different fields")
|
|
TEST_VARIATION(10, L"Two optimized, using different fields")
|
|
TEST_VARIATION(11, L"Two non-optimized, using same fields")
|
|
TEST_VARIATION(12, L"Multiple bindings for same column in one accessor")
|
|
TEST_VARIATION(13, L"All types bound BY_REF, without DBMEMOWNER_PROVIDEROWNED")
|
|
TEST_VARIATION(14, L"Fixed types bound BY_REF, without DBMEMOWNER_PROVIDEROWNED")
|
|
TEST_VARIATION(15, L"Variable types bound BY_REF, without DBMEMOWNER_PROVIDEROWNED")
|
|
TEST_VARIATION(16, L"All types bound BY_REF, with DBMEMOWNER_PROVIDEROWNED")
|
|
TEST_VARIATION(17, L"Fixed types bound BY_REF, with DBMEMOWNER_PROVIDEROWNED")
|
|
TEST_VARIATION(18, L"Variable types bound BY_REF, with DBMEMOWNER_PROVIDEROWNED")
|
|
TEST_VARIATION(19, L"No types bound BY_REF, with DBMEMOWNER_PROVIDEROWNED")
|
|
TEST_VARIATION(20, L"Use accessor after release rows")
|
|
TEST_VARIATION(21, L"dwFlags: DBBINDFLAG_HTML")
|
|
TEST_VARIATION(22, L"DBACCESSOR_INHERITED - Or'd with DBACCESSOR_OPTIMIZED")
|
|
END_TEST_CASE()
|
|
#undef THE_CLASS
|
|
// }} TCW_TESTCASE_END
|
|
// }} TCW_TEST_CASE_MAP_END
|
|
|
|
|
|
// {{ TCW_TEST_CASE_MAP(TCCreateValidParamAccessors)
|
|
//--------------------------------------------------------------------
|
|
// @class Creation of valid parameter accessors
|
|
//
|
|
class TCCreateValidParamAccessors : public CAccessor {
|
|
private:
|
|
// @cmember Static array of variations
|
|
DECLARE_TEST_CASE_DATA();
|
|
|
|
// @cmember Save global table pointer for the testcase
|
|
CTable *m_pSaveTable;
|
|
|
|
public:
|
|
// {{ TCW_DECLARE_FUNCS
|
|
// @cmember Execution Routine
|
|
DECLARE_TEST_CASE_FUNCS(TCCreateValidParamAccessors,CAccessor);
|
|
// }} TCW_DECLARE_FUNCS_END
|
|
|
|
// @cmember Initialization Routine
|
|
virtual BOOL Init();
|
|
// @cmember Termination Routine
|
|
virtual BOOL Terminate();
|
|
|
|
// {{ TCW_TESTVARS()
|
|
// @cmember ROWDATA and PARAMETERDATA accessor
|
|
int Variation_1();
|
|
// @cmember Null Parameter Accessor
|
|
int Variation_2();
|
|
// @cmember dwPart - DBCOLUMPART_VALUE
|
|
int Variation_3();
|
|
// @cmember dwPart - DBCOLUMPART_LENGTH
|
|
int Variation_4();
|
|
// @cmember dwPart - DBCOLUMPART_STATUS
|
|
int Variation_5();
|
|
// @cmember dwPart - DBCOLUMPART_VALUE | DBPART_STATUS
|
|
int Variation_6();
|
|
// @cmember dwPart - DBCOLUMPART_LENGTH | DBPART_STATUS | DBPART_VALUE
|
|
int Variation_7();
|
|
// @cmember One optimized, one non optimized, using same fields
|
|
int Variation_8();
|
|
// @cmember One non-optimized, one optimized, using same fields - different creation sequence
|
|
int Variation_9();
|
|
// @cmember Two non-optimized, using same fields
|
|
int Variation_10();
|
|
// @cmember All searchable cols BY_REF, without DBMEMOWNER_PROVIDEROWNED
|
|
int Variation_11();
|
|
// @cmember More than 256 parameters
|
|
int Variation_12();
|
|
// @cmember Use DBBINDFLAGS_HTML in parameter accessor
|
|
int Variation_13();
|
|
// @cmember DBACCESSOR_INHERITED - Or'd with DBACCESSOR_OPTIMIZED
|
|
int Variation_14();
|
|
// }} TCW_TESTVARS_END
|
|
};
|
|
// {{ TCW_TESTCASE(TCCreateValidParamAccessors)
|
|
#define THE_CLASS TCCreateValidParamAccessors
|
|
BEG_TEST_CASE(TCCreateValidParamAccessors, CAccessor, L"Creation of valid parameter accessors")
|
|
TEST_VARIATION(1, L"ROWDATA and PARAMETERDATA accessor")
|
|
TEST_VARIATION(2, L"Null Parameter Accessor")
|
|
TEST_VARIATION(3, L"dwPart - DBCOLUMPART_VALUE")
|
|
TEST_VARIATION(4, L"dwPart - DBCOLUMPART_LENGTH")
|
|
TEST_VARIATION(5, L"dwPart - DBCOLUMPART_STATUS")
|
|
TEST_VARIATION(6, L"dwPart - DBCOLUMPART_VALUE | DBPART_STATUS")
|
|
TEST_VARIATION(7, L"dwPart - DBCOLUMPART_LENGTH | DBPART_STATUS | DBPART_VALUE")
|
|
TEST_VARIATION(8, L"One optimized, one non optimized, using same fields")
|
|
TEST_VARIATION(9, L"One non-optimized, one optimized, using same fields - different creation sequence")
|
|
TEST_VARIATION(10, L"Two non-optimized, using same fields")
|
|
TEST_VARIATION(11, L"All searchable cols BY_REF, without DBMEMOWNER_PROVIDEROWNED")
|
|
TEST_VARIATION(12, L"More than 256 parameters")
|
|
TEST_VARIATION(13, L"Use DBBINDFLAGS_HTML in parameter accessor")
|
|
TEST_VARIATION(14, L"DBACCESSOR_INHERITED - Or'd with DBACCESSOR_OPTIMIZED")
|
|
END_TEST_CASE()
|
|
#undef THE_CLASS
|
|
// }} TCW_TESTCASE_END
|
|
// }} TCW_TEST_CASE_MAP_END
|
|
|
|
|
|
// {{ TCW_TEST_CASE_MAP(TCAccessorSequencing)
|
|
//--------------------------------------------------------------------
|
|
// @class Accessors created and used in various sequences
|
|
//
|
|
class TCAccessorSequencing : public CAccessor {
|
|
private:
|
|
// @cmember Static array of variations
|
|
DECLARE_TEST_CASE_DATA();
|
|
|
|
public:
|
|
// {{ TCW_DECLARE_FUNCS
|
|
// @cmember Execution Routine
|
|
DECLARE_TEST_CASE_FUNCS(TCAccessorSequencing,CAccessor);
|
|
// }} TCW_DECLARE_FUNCS_END
|
|
|
|
// @cmember Initialization Routine
|
|
virtual BOOL Init();
|
|
// @cmember Termination Routine
|
|
virtual BOOL Terminate();
|
|
|
|
// {{ TCW_TESTVARS()
|
|
// @cmember One accessor created on command, one on rowset
|
|
int Variation_1();
|
|
// @cmember One accessor created on command, one on rowset, using different fields
|
|
int Variation_2();
|
|
// @cmember Two ROWDATA accessors on command object, one before and one after execute
|
|
int Variation_3();
|
|
// @cmember Create and use accessor after Setting command
|
|
int Variation_4();
|
|
// @cmember Create and use accessor after reading data via IRowset
|
|
int Variation_5();
|
|
// @cmember Create and use accessor after GetData
|
|
int Variation_6();
|
|
// @cmember ReleaseAccessor at different times
|
|
int Variation_7();
|
|
// @cmember Use Command accessor after freeing command object
|
|
int Variation_8();
|
|
// @cmember CreateAccessor from GetBindings and Release, validate pBinding
|
|
int Variation_9();
|
|
// @cmember CreateAccessor on new command object
|
|
int Variation_10();
|
|
// }} TCW_TESTVARS_END
|
|
};
|
|
// {{ TCW_TESTCASE(TCAccessorSequencing)
|
|
#define THE_CLASS TCAccessorSequencing
|
|
BEG_TEST_CASE(TCAccessorSequencing, CAccessor, L"Accessors created and used in various sequences")
|
|
TEST_VARIATION(1, L"One accessor created on command, one on rowset")
|
|
TEST_VARIATION(2, L"One accessor created on command, one on rowset, using different fields")
|
|
TEST_VARIATION(3, L"Two ROWDATA accessors on command object, one before and one after execute")
|
|
TEST_VARIATION(4, L"Create and use accessor after Setting command")
|
|
TEST_VARIATION(5, L"Create and use accessor after reading data via IRowset")
|
|
TEST_VARIATION(6, L"Create and use accessor after GetData")
|
|
TEST_VARIATION(7, L"ReleaseAccessor at different times")
|
|
TEST_VARIATION(8, L"Use Command accessor after freeing command object")
|
|
TEST_VARIATION(9, L"CreateAccessor from GetBindings and Release, validate pBinding")
|
|
TEST_VARIATION(10, L"CreateAccessor on new command object")
|
|
END_TEST_CASE()
|
|
#undef THE_CLASS
|
|
// }} TCW_TESTCASE_END
|
|
// }} TCW_TEST_CASE_MAP_END
|
|
|
|
|
|
// {{ TCW_TEST_CASE_MAP(TCBookMarkRowset)
|
|
//--------------------------------------------------------------------
|
|
// @class Create accessors for rowsets with bookmarks
|
|
//
|
|
class TCBookMarkRowset : public CAccessor {
|
|
private:
|
|
// @cmember Static array of variations
|
|
DECLARE_TEST_CASE_DATA();
|
|
|
|
public:
|
|
// {{ TCW_DECLARE_FUNCS
|
|
// @cmember Execution Routine
|
|
DECLARE_TEST_CASE_FUNCS(TCBookMarkRowset,CAccessor);
|
|
// }} TCW_DECLARE_FUNCS_END
|
|
|
|
// @cmember Initialization Routine
|
|
virtual BOOL Init();
|
|
// @cmember Termination Routine
|
|
virtual BOOL Terminate();
|
|
|
|
// {{ TCW_TESTVARS()
|
|
// @cmember Bind bookmark column with ROWDATA
|
|
int Variation_1();
|
|
// }} TCW_TESTVARS_END
|
|
};
|
|
// {{ TCW_TESTCASE(TCBookMarkRowset)
|
|
#define THE_CLASS TCBookMarkRowset
|
|
BEG_TEST_CASE(TCBookMarkRowset, CAccessor, L"Create accessors for rowsets with bookmarks")
|
|
TEST_VARIATION(1, L"Bind bookmark column with ROWDATA")
|
|
END_TEST_CASE()
|
|
#undef THE_CLASS
|
|
// }} TCW_TESTCASE_END
|
|
// }} TCW_TEST_CASE_MAP_END
|
|
|
|
|
|
// {{ TCW_TEST_CASE_MAP(TCGetBindingsRtnVals)
|
|
//--------------------------------------------------------------------
|
|
// @class Return values for all GetBindings error conditions
|
|
//
|
|
class TCGetBindingsRtnVals : public CAccessor {
|
|
private:
|
|
// @cmember Static array of variations
|
|
DECLARE_TEST_CASE_DATA();
|
|
|
|
public:
|
|
// {{ TCW_DECLARE_FUNCS
|
|
// @cmember Execution Routine
|
|
DECLARE_TEST_CASE_FUNCS(TCGetBindingsRtnVals,CAccessor);
|
|
// }} TCW_DECLARE_FUNCS_END
|
|
|
|
// @cmember Initialization Routine
|
|
virtual BOOL Init();
|
|
// @cmember Termination Routine
|
|
virtual BOOL Terminate();
|
|
|
|
// {{ TCW_TESTVARS()
|
|
// @cmember E_INVALIDARG - Null pdwAccessorFlags
|
|
int Variation_1();
|
|
// @cmember E_INVALIDARG - Null pcBindings
|
|
int Variation_2();
|
|
// @cmember E_INVALIDARG - Null prgBindings
|
|
int Variation_3();
|
|
// @cmember DB_E_BADACCESSORHANDLE - Null hAccessor
|
|
int Variation_4();
|
|
// @cmember DB_E_BADACCESSORHANDLE - Previously released accessor for hAccessor
|
|
int Variation_5();
|
|
// }} TCW_TESTVARS_END
|
|
};
|
|
// {{ TCW_TESTCASE(TCGetBindingsRtnVals)
|
|
#define THE_CLASS TCGetBindingsRtnVals
|
|
BEG_TEST_CASE(TCGetBindingsRtnVals, CAccessor, L"Return values for all GetBindings error conditions")
|
|
TEST_VARIATION(1, L"E_INVALIDARG - Null pdwAccessorFlags")
|
|
TEST_VARIATION(2, L"E_INVALIDARG - Null pcBindings")
|
|
TEST_VARIATION(3, L"E_INVALIDARG - Null prgBindings")
|
|
TEST_VARIATION(4, L"DB_E_BADACCESSORHANDLE - Null hAccessor")
|
|
TEST_VARIATION(5, L"DB_E_BADACCESSORHANDLE - Previously released accessor for hAccessor")
|
|
END_TEST_CASE()
|
|
#undef THE_CLASS
|
|
// }} TCW_TESTCASE_END
|
|
// }} TCW_TEST_CASE_MAP_END
|
|
|
|
|
|
// {{ TCW_TEST_CASE_MAP(TCReleaseAccessorRtnVals)
|
|
//--------------------------------------------------------------------
|
|
// @class Return values for all ReleaseAccessor error conditions
|
|
//
|
|
class TCReleaseAccessorRtnVals : public CAccessor {
|
|
private:
|
|
// @cmember Static array of variations
|
|
DECLARE_TEST_CASE_DATA();
|
|
|
|
public:
|
|
// {{ TCW_DECLARE_FUNCS
|
|
// @cmember Execution Routine
|
|
DECLARE_TEST_CASE_FUNCS(TCReleaseAccessorRtnVals,CAccessor);
|
|
// }} TCW_DECLARE_FUNCS_END
|
|
|
|
// @cmember Initialization Routine
|
|
virtual BOOL Init();
|
|
// @cmember Termination Routine
|
|
virtual BOOL Terminate();
|
|
|
|
// {{ TCW_TESTVARS()
|
|
// @cmember S_OK - Release Rowset without releasing rowset Accessor
|
|
int Variation_1();
|
|
// @cmember DB_E_BADACCESSORHANDLE - Previously released accessor for hAccessor
|
|
int Variation_2();
|
|
// @cmember DB_E_OPENOBJECT - Release command accessor while rowset is open
|
|
int Variation_3();
|
|
// }} TCW_TESTVARS_END
|
|
};
|
|
// {{ TCW_TESTCASE(TCReleaseAccessorRtnVals)
|
|
#define THE_CLASS TCReleaseAccessorRtnVals
|
|
BEG_TEST_CASE(TCReleaseAccessorRtnVals, CAccessor, L"Return values for all ReleaseAccessor error conditions")
|
|
TEST_VARIATION(1, L"S_OK - Release Rowset without releasing rowset Accessor")
|
|
TEST_VARIATION(2, L"DB_E_BADACCESSORHANDLE - Previously released accessor for hAccessor")
|
|
TEST_VARIATION(3, L"DB_E_OPENOBJECT - Release command accessor while rowset is open")
|
|
END_TEST_CASE()
|
|
#undef THE_CLASS
|
|
// }} TCW_TESTCASE_END
|
|
// }} TCW_TEST_CASE_MAP_END
|
|
|
|
|
|
// {{ TCW_TEST_CASE_MAP(TCDeferredColumns)
|
|
//--------------------------------------------------------------------
|
|
// @class Use of Deferred and CacheDeferred properties
|
|
//
|
|
class TCDeferredColumns : public CAccessor {
|
|
private:
|
|
|
|
// @cmember Flag indicating if Deferred column property is supported
|
|
BOOL m_fDeferredSupported;
|
|
|
|
// @cmember Flag indicating if Deferred column caching property is supported
|
|
BOOL m_fCacheSupported;
|
|
|
|
// @cmember Accessor with only fixed length columns bound
|
|
HACCESSOR m_FixedAccessor;
|
|
|
|
// @cmember Accessor with only variable length columns bound
|
|
HACCESSOR m_VariableAccessor;
|
|
|
|
// @cmember Accessor with all rowset columns bound, used on GetRowset
|
|
HACCESSOR m_GetAllAccessor;
|
|
|
|
// @cmember Accessor with all rowset columns bound, used on SetRowset
|
|
HACCESSOR m_SetAllAccessor;
|
|
|
|
// @cmember Bindings for FixedAccessor
|
|
DBBINDING * m_rgFixedBindings;
|
|
|
|
// @cmember Bindings for VariableAccessor
|
|
DBBINDING * m_rgVariableBindings;
|
|
|
|
// @cmember Bindings for GetAllAccessor
|
|
DBBINDING * m_rgGetAllBindings;
|
|
|
|
// @cmember Bindings for SetAllAccessor
|
|
DBBINDING * m_rgSetAllBindings;
|
|
|
|
// @cmember Count of bindings in m_rgFixedBindings
|
|
DBCOUNTITEM m_cFixedBindings;
|
|
|
|
// @cmember Count of bindings in m_rgVariableBindings
|
|
DBCOUNTITEM m_cVariableBindings;
|
|
|
|
// @cmember Count of bindings in m_rgGetAllBindings
|
|
DBCOUNTITEM m_cGetAllBindings;
|
|
|
|
// @cmember Count of bindings in m_rgSetAllBindings
|
|
DBCOUNTITEM m_cSetAllBindings;
|
|
|
|
// @cmember Count of bytes needed for a single row using m_FixedAccessor
|
|
DBLENGTH m_cbFixedRowSize;
|
|
|
|
// @cmember Count of bytes needed for a single row using m_VariableAccessor
|
|
DBLENGTH m_cbVariableRowSize;
|
|
|
|
// @cmember Count of bytes needed for a single row using m_GetAllAccessor
|
|
DBLENGTH m_cbGetAllRowSize;
|
|
|
|
// @cmember Count of bytes needed for a single row using m_SetAllAccessor
|
|
DBLENGTH m_cbSetAllRowSize;
|
|
|
|
// @cmember IRowset interface to use for retrieving data
|
|
IRowset * m_pGetIRowset;
|
|
|
|
// @cmember IRowset interface to use for setting data concurrently to back end
|
|
IRowset * m_pSetIRowset;
|
|
|
|
// @cmember IRowsetChange interface for actual setting of data on set rowset
|
|
IRowsetChange * m_pSetIRowsetChange;
|
|
|
|
// @cmember Array of columns ids for rowset
|
|
DBID * m_rgDBIDs;
|
|
|
|
//@cmember Encapsulated rowset object, used to Set Data
|
|
//so the data differs from what is cached.
|
|
CSetRowsetObject * m_pSetRowset;
|
|
|
|
// @cmember Static array of variations
|
|
DECLARE_TEST_CASE_DATA();
|
|
|
|
public:
|
|
// {{ TCW_DECLARE_FUNCS
|
|
// @cmember Execution Routine
|
|
DECLARE_TEST_CASE_FUNCS(TCDeferredColumns,CAccessor);
|
|
// }} TCW_DECLARE_FUNCS_END
|
|
|
|
// @cmember Initialization Routine
|
|
virtual BOOL Init();
|
|
// @cmember Termination Routine
|
|
virtual BOOL Terminate();
|
|
|
|
//@cmember Sets row of data in table to PRIMARY or SECONDARY
|
|
HRESULT SetData(EVALUE eValue=PRIMARY);
|
|
|
|
//@cmember Releases current m_pGetIRowset, sets deferred properties requested and generates new rowset
|
|
HRESULT SetDeferredProperties(BOOL fDeferred, BOOL fCacheDeferred, DBCOUNTITEM cBindings, DBBINDING * rgBindings);
|
|
|
|
//@cmember Copies test case info from testcase to encapsulated CRowset object
|
|
void CopyTestCaseInfo(CTestCases * pTC);
|
|
|
|
// {{ TCW_TESTVARS()
|
|
// @cmember Deferred on, CacheDeferred off - All Columns
|
|
int Variation_1();
|
|
// @cmember Deferred on, CacheDeferred on - Fixed Columns
|
|
int Variation_2();
|
|
// @cmember Deferred on, CacheDeferred on - Variable Columns
|
|
int Variation_3();
|
|
// @cmember Deferred on, CacheDeferred on - All Columns
|
|
int Variation_4();
|
|
// @cmember Deferred off, CacheDeferred on - All Columns
|
|
int Variation_5();
|
|
// }} TCW_TESTVARS_END
|
|
};
|
|
// {{ TCW_TESTCASE(TCDeferredColumns)
|
|
#define THE_CLASS TCDeferredColumns
|
|
BEG_TEST_CASE(TCDeferredColumns, CAccessor, L"Use of Deferred and CacheDeferred properties")
|
|
TEST_VARIATION(1, L"Deferred on, CacheDeferred off - All Columns")
|
|
TEST_VARIATION(2, L"Deferred on, CacheDeferred on - Fixed Columns")
|
|
TEST_VARIATION(3, L"Deferred on, CacheDeferred on - Variable Columns")
|
|
TEST_VARIATION(4, L"Deferred on, CacheDeferred on - All Columns")
|
|
TEST_VARIATION(5, L"Deferred off, CacheDeferred on - All Columns")
|
|
END_TEST_CASE()
|
|
#undef THE_CLASS
|
|
// }} TCW_TESTCASE_END
|
|
// }} TCW_TEST_CASE_MAP_END
|
|
|
|
|
|
// {{ TCW_TEST_CASE_MAP(TCCommandAccessorTransactions)
|
|
//--------------------------------------------------------------------
|
|
// @class Commit/Abort behavior for Command Accessors
|
|
//
|
|
class TCCommandAccessorTransactions : public CTransaction {
|
|
private:
|
|
// @cmember Static array of variations
|
|
DECLARE_TEST_CASE_DATA();
|
|
|
|
public:
|
|
// {{ TCW_DECLARE_FUNCS
|
|
// @cmember Execution Routine
|
|
DECLARE_TEST_CASE_FUNCS(TCCommandAccessorTransactions,CTransaction);
|
|
// }} TCW_DECLARE_FUNCS_END
|
|
|
|
//Tests commit/abort with respect to IAccessor on commands
|
|
int TestTxn(ETXN eTxn, BOOL fRetaining);
|
|
|
|
//@cmember IAccessor on command object
|
|
IAccessor * m_pIAccessor;
|
|
|
|
//@cmember Accessor handle
|
|
HACCESSOR m_hAccessor;
|
|
|
|
//@cmember Array of bindings to use for CreateAccessor
|
|
DBBINDING m_rgBindings[1];
|
|
|
|
//@cmember Count of bindings in binding array
|
|
DBCOUNTITEM m_cBindings;
|
|
|
|
//@cmember Holds the size of one row of data for the accessor
|
|
DBLENGTH m_cbRowSize;
|
|
|
|
//@cmember Holds flags for the accessor
|
|
ULONG m_dwFlags;
|
|
|
|
//@cmember Pointer to array of bindings from GetBindings
|
|
DBBINDING * m_rgGetBindings;
|
|
|
|
// @cmember Initialization Routine
|
|
virtual BOOL Init();
|
|
// @cmember Termination Routine
|
|
virtual BOOL Terminate();
|
|
|
|
// {{ TCW_TESTVARS()
|
|
// @cmember Commit Retaining
|
|
int Variation_1();
|
|
// @cmember Commit Non Retaining
|
|
int Variation_2();
|
|
// @cmember Abort Retaining
|
|
int Variation_3();
|
|
// @cmember Abort Non Retaining
|
|
int Variation_4();
|
|
// }} TCW_TESTVARS_END
|
|
};
|
|
// {{ TCW_TESTCASE(TCCommandAccessorTransactions)
|
|
#define THE_CLASS TCCommandAccessorTransactions
|
|
BEG_TEST_CASE(TCCommandAccessorTransactions, CTransaction, L"Commit/Abort behavior for Command Accessors")
|
|
TEST_VARIATION(1, L"Commit Retaining")
|
|
TEST_VARIATION(2, L"Commit Non Retaining")
|
|
TEST_VARIATION(3, L"Abort Retaining")
|
|
TEST_VARIATION(4, L"Abort Non Retaining")
|
|
END_TEST_CASE()
|
|
#undef THE_CLASS
|
|
// }} TCW_TESTCASE_END
|
|
// }} TCW_TEST_CASE_MAP_END
|
|
|
|
|
|
// {{ TCW_TEST_CASE_MAP(TCRowsetAccessorTransactions)
|
|
//--------------------------------------------------------------------
|
|
// @class Commit/Abort behavior for Rowset Accessors
|
|
//
|
|
class TCRowsetAccessorTransactions : public CTransaction {
|
|
private:
|
|
// @cmember Static array of variations
|
|
DECLARE_TEST_CASE_DATA();
|
|
|
|
public:
|
|
// {{ TCW_DECLARE_FUNCS
|
|
// @cmember Execution Routine
|
|
DECLARE_TEST_CASE_FUNCS(TCRowsetAccessorTransactions,CTransaction);
|
|
// }} TCW_DECLARE_FUNCS_END
|
|
|
|
//@cmember Tests zombie IAccessor states on rowset
|
|
int TCRowsetAccessorTransactions::TestTxn(ETXN eTxn, BOOL fRetaining);
|
|
|
|
//@cmember IAccessor on rowset object
|
|
IAccessor * m_pIAccessor;
|
|
|
|
//@cmember Accessor handle
|
|
HACCESSOR m_hAccessor;
|
|
|
|
//@cmember Array of bindings to use for CreateAccessor
|
|
DBBINDING m_rgBindings[1];
|
|
|
|
//@cmember Count of bindings in binding array
|
|
DBCOUNTITEM m_cBindings;
|
|
|
|
//@cmember Holds the size of one row of data for the accessor
|
|
ULONG m_cbRowSize;
|
|
|
|
//@cmember Holds flags for the accessor
|
|
ULONG m_dwFlags;
|
|
|
|
//@cmember Pointer to array of bindings from GetBindings
|
|
DBBINDING * m_rgGetBindings;
|
|
|
|
// @cmember Initialization Routine
|
|
virtual BOOL Init();
|
|
// @cmember Termination Routine
|
|
virtual BOOL Terminate();
|
|
|
|
// {{ TCW_TESTVARS()
|
|
// @cmember Commit Retaining
|
|
int Variation_1();
|
|
// @cmember Commit Non Retaining
|
|
int Variation_2();
|
|
// @cmember Abort Retaining
|
|
int Variation_3();
|
|
// @cmember Abort Non Retaining
|
|
int Variation_4();
|
|
// }} TCW_TESTVARS_END
|
|
};
|
|
// {{ TCW_TESTCASE(TCRowsetAccessorTransactions)
|
|
#define THE_CLASS TCRowsetAccessorTransactions
|
|
BEG_TEST_CASE(TCRowsetAccessorTransactions, CTransaction, L"Commit/Abort behavior for Rowset Accessors")
|
|
TEST_VARIATION(1, L"Commit Retaining")
|
|
TEST_VARIATION(2, L"Commit Non Retaining")
|
|
TEST_VARIATION(3, L"Abort Retaining")
|
|
TEST_VARIATION(4, L"Abort Non Retaining")
|
|
END_TEST_CASE()
|
|
#undef THE_CLASS
|
|
// }} TCW_TESTCASE_END
|
|
// }} TCW_TEST_CASE_MAP_END
|
|
|
|
|
|
// {{ TCW_TEST_CASE_MAP(TCExtendedErrors)
|
|
//--------------------------------------------------------------------
|
|
// @class Extended Errors
|
|
//
|
|
class TCExtendedErrors : public CAccessor {
|
|
private:
|
|
// @cmember Static array of variations
|
|
DECLARE_TEST_CASE_DATA();
|
|
|
|
public:
|
|
// {{ TCW_DECLARE_FUNCS
|
|
// @cmember Execution Routine
|
|
DECLARE_TEST_CASE_FUNCS(TCExtendedErrors,CAccessor);
|
|
// }} TCW_DECLARE_FUNCS_END
|
|
|
|
|
|
// @cmember Initialization Routine
|
|
virtual BOOL Init();
|
|
// @cmember Termination Routine
|
|
virtual BOOL Terminate();
|
|
|
|
// {{ TCW_TESTVARS()
|
|
// @cmember Valid IAccessor calls with previous error object existing.
|
|
int Variation_1();
|
|
// @cmember Invalid IAccessor calls with previous error object existing
|
|
int Variation_2();
|
|
// @cmember Invalid IAccessor calls with no previous error object existing
|
|
int Variation_3();
|
|
// }} TCW_TESTVARS_END
|
|
};
|
|
// {{ TCW_TESTCASE(TCExtendedErrors)
|
|
#define THE_CLASS TCExtendedErrors
|
|
BEG_TEST_CASE(TCExtendedErrors, CAccessor, L"Extended Errors")
|
|
TEST_VARIATION(1, L"Valid IAccessor calls with previous error object existing.")
|
|
TEST_VARIATION(2, L"Invalid IAccessor calls with previous error object existing")
|
|
TEST_VARIATION(3, L"Invalid IAccessor calls with no previous error object existing")
|
|
END_TEST_CASE()
|
|
#undef THE_CLASS
|
|
// }} TCW_TESTCASE_END
|
|
// }} TCW_TEST_CASE_MAP_END
|
|
|
|
|
|
// {{ TCW_TEST_CASE_MAP(TCCrtRtnValsBeforeGetRows)
|
|
//--------------------------------------------------------------------
|
|
// @class Return values for all CreateAccessor error conditions
|
|
//
|
|
class TCCrtRtnValsBeforeGetRows : public CAccessor {
|
|
private:
|
|
// @cmember Static array of variations
|
|
DECLARE_TEST_CASE_DATA();
|
|
|
|
public:
|
|
// {{ TCW_DECLARE_FUNCS
|
|
// @cmember Execution Routine
|
|
DECLARE_TEST_CASE_FUNCS(TCCrtRtnValsBeforeGetRows,CAccessor);
|
|
// }} TCW_DECLARE_FUNCS_END
|
|
|
|
// @cmember Initialization Routine
|
|
virtual BOOL Init();
|
|
// @cmember Termination Routine
|
|
virtual BOOL Terminate();
|
|
|
|
// {{ TCW_TESTVARS()
|
|
// @cmember DB_E_BADBINDINFO - PASSBYREF without correct buffer format
|
|
int Variation_1();
|
|
// @cmember DB_E_BADBINDINFO - DBMEMOWNER_PROVIDEROWNED with DBTYPE not matching provider's
|
|
int Variation_2();
|
|
// @cmember DB_E_BADBINDINFO - Accessor with invalid coersion for column in existing optimized accessor
|
|
int Variation_3();
|
|
// @cmember DB_E_BADORDINAL - iOrdinal of largest column number + 1
|
|
int Variation_4();
|
|
// @cmember DB_E_BADORDINAL - iOrdinal of max value for ULONG
|
|
int Variation_5();
|
|
// @cmember DB_E_BADORDINAL - iOrdinal = 0 for ROWDATA accessor without bookmarks
|
|
int Variation_6();
|
|
// @cmember DB_E_BADBINDINFO - Some bindings succeeding others failing
|
|
int Variation_7();
|
|
// }} TCW_TESTVARS_END
|
|
};
|
|
// {{ TCW_TESTCASE(TCCrtRtnValsBeforeGetRows)
|
|
#define THE_CLASS TCCrtRtnValsBeforeGetRows
|
|
BEG_TEST_CASE(TCCrtRtnValsBeforeGetRows, CAccessor, L"Return values for all CreateAccessor error conditions")
|
|
TEST_VARIATION(1, L"DB_E_BADBINDINFO - PASSBYREF without correct buffer format")
|
|
TEST_VARIATION(2, L"DB_E_BADBINDINFO - DBMEMOWNER_PROVIDEROWNED with DBTYPE not matching provider's")
|
|
TEST_VARIATION(3, L"DB_E_BADBINDINFO - Accessor with invalid coersion for column in existing optimized accessor")
|
|
TEST_VARIATION(4, L"DB_E_BADORDINAL - iOrdinal of largest column number + 1")
|
|
TEST_VARIATION(5, L"DB_E_BADORDINAL - iOrdinal of max value for ULONG")
|
|
TEST_VARIATION(6, L"DB_E_BADORDINAL - iOrdinal = 0 for ROWDATA accessor without bookmarks")
|
|
TEST_VARIATION(7, L"DB_E_BADBINDINFO - Some bindings succeeding others failing")
|
|
END_TEST_CASE()
|
|
#undef THE_CLASS
|
|
// }} TCW_TESTCASE_END
|
|
// }} TCW_TEST_CASE_MAP_END
|
|
|
|
|
|
// {{ TCW_TEST_CASE_MAP(TCAddRefAccessor)
|
|
//--------------------------------------------------------------------
|
|
// @class Test the AddREfAccessor Method
|
|
//
|
|
class TCAddRefAccessor : public CAccessor {
|
|
private:
|
|
// @cmember Static array of variations
|
|
DECLARE_TEST_CASE_DATA();
|
|
|
|
public:
|
|
// {{ TCW_DECLARE_FUNCS
|
|
// @cmember Execution Routine
|
|
DECLARE_TEST_CASE_FUNCS(TCAddRefAccessor,CAccessor);
|
|
// }} TCW_DECLARE_FUNCS_END
|
|
|
|
// @cmember Initialization Routine
|
|
virtual BOOL Init();
|
|
// @cmember Termination Routine
|
|
virtual BOOL Terminate();
|
|
|
|
// {{ TCW_TESTVARS()
|
|
// @cmember Regular Addreff on an accessor, S_OK
|
|
int Variation_1();
|
|
// @cmember Addref on Command and Rowset object.
|
|
int Variation_2();
|
|
// @cmember NULL for pcRefCount arguments.
|
|
int Variation_3();
|
|
// @cmember Invalid Accessor
|
|
int Variation_4();
|
|
// @cmember Release accessor on a rowset object.
|
|
int Variation_5();
|
|
// }} TCW_TESTVARS_END
|
|
};
|
|
// {{ TCW_TESTCASE(TCAddRefAccessor)
|
|
#define THE_CLASS TCAddRefAccessor
|
|
BEG_TEST_CASE(TCAddRefAccessor, CAccessor, L"Test the AddREfAccessor Method")
|
|
TEST_VARIATION(1, L"Regular Addreff on an accessor, S_OK")
|
|
TEST_VARIATION(2, L"Addref on Command and Rowset object.")
|
|
TEST_VARIATION(3, L"NULL for pcRefCount arguments.")
|
|
TEST_VARIATION(4, L"Invalid Accessor")
|
|
TEST_VARIATION(5, L"Release accessor on a rowset object.")
|
|
END_TEST_CASE()
|
|
#undef THE_CLASS
|
|
// }} TCW_TESTCASE_END
|
|
// }} TCW_TEST_CASE_MAP_END
|
|
|
|
|
|
// {{ TCW_TEST_CASE_MAP(TCAccessorOnAlteredTable)
|
|
//--------------------------------------------------------------------
|
|
// @class Test to test the validity of accessors once rowset is modified.
|
|
//
|
|
class TCAccessorOnAlteredTable : public CAccessor {
|
|
private:
|
|
// @cmember Static array of variations
|
|
DECLARE_TEST_CASE_DATA();
|
|
|
|
// CLASS VARIABLES
|
|
|
|
// @cmember Table object for Alter Table test case
|
|
CTable * m_pAT_Table;
|
|
|
|
// @cmember Command text interface pointer.
|
|
ICommandText *m_pATICommandText;
|
|
|
|
// @cmember Rowset interface pointer.
|
|
IRowset *m_pATIRowset;
|
|
|
|
// @cmember ColumnsRowsetInfo Rowset pointer.
|
|
IRowset *m_pIColumnsRowsetInfo;
|
|
|
|
// @cmember IColumnsInfo interface pointer.
|
|
IColumnsInfo *m_pATIColumnsInfo;
|
|
|
|
// @cmember IAccessor Interface pointer.
|
|
IAccessor *m_pATIAccessor ;
|
|
|
|
// @cmember IColumnsRowset interface pointer.
|
|
IColumnsRowset *m_pATIColumnsRowset;
|
|
|
|
// @cmbember Array for storing bindings for the table.
|
|
DBBINDING m_rgATDbBindings[3];
|
|
|
|
// @cmember Rowsize for Create accessor.
|
|
DBLENGTH m_cbRowSize ; // Some safe size.
|
|
|
|
// @cmember Number of bindings.
|
|
ULONG m_cATDbBindings;
|
|
|
|
// @cmember accessor on the table.
|
|
HACCESSOR m_hATAccessor;
|
|
|
|
// @cmember Number of members returned by IcolumnsInfo.
|
|
DBORDINAL m_cColumnsInfo;
|
|
|
|
// @cmember Column information returned by IColumnsInfo
|
|
DBCOLUMNINFO *m_rgColumnsInfo;
|
|
|
|
// @cmember Strings buffer.
|
|
OLECHAR *m_pStringsBuffer;
|
|
|
|
// @cmember Number of rows obtained for ColumnsRowset.
|
|
DBCOUNTITEM m_cColumnsRowsetInfoObtained;
|
|
|
|
// @cmember HROWS's for ColumnsRowset.
|
|
HROW m_rgColumnsRowsetInfohRows[3]; // 2 hrows for Now One for Later (after alter table).
|
|
|
|
// @cmember Mapping of bindings-to-columns for data comparison.
|
|
DB_LORDINAL m_rgColMap[2];
|
|
|
|
// @cmember Object name used, may be View or Procedure name
|
|
WCHAR * m_pwszObjName;
|
|
|
|
public:
|
|
// {{ TCW_DECLARE_FUNCS
|
|
// @cmember Execution Routine
|
|
DECLARE_TEST_CASE_FUNCS(TCAccessorOnAlteredTable,CAccessor);
|
|
// }} TCW_DECLARE_FUNCS_END
|
|
|
|
// @cmember Initialization Routine
|
|
virtual BOOL Init();
|
|
// @cmember Termination Routine
|
|
virtual BOOL Terminate();
|
|
|
|
// {{ TCW_TESTVARS()
|
|
// @cmember Test to verify the validity of accessors on an altered rowset.
|
|
int Variation_1();
|
|
// }} TCW_TESTVARS_END
|
|
};
|
|
// {{ TCW_TESTCASE(TCAccessorOnAlteredTable)
|
|
#define THE_CLASS TCAccessorOnAlteredTable
|
|
BEG_TEST_CASE(TCAccessorOnAlteredTable, CAccessor, L"Test to test the validity of accessors once rowset is modified.")
|
|
TEST_VARIATION(1, L"Test to verify the validity of accessors on an altered rowset.")
|
|
END_TEST_CASE()
|
|
#undef THE_CLASS
|
|
// }} TCW_TESTCASE_END
|
|
// }} TCW_TEST_CASE_MAP_END
|
|
|
|
|
|
// }} END_DECLARE_TEST_CASES()
|
|
|
|
// {{ TCW_TESTMODULE(ThisModule)
|
|
TEST_MODULE(14, ThisModule, gwszModuleDescrip)
|
|
TEST_CASE(1, TCCrtRtnValsAfterGetRows)
|
|
TEST_CASE(2, TCCreateValidRowAccessors)
|
|
TEST_CASE(3, TCCreateValidParamAccessors)
|
|
TEST_CASE(4, TCAccessorSequencing)
|
|
TEST_CASE(5, TCBookMarkRowset)
|
|
TEST_CASE(6, TCGetBindingsRtnVals)
|
|
TEST_CASE(7, TCReleaseAccessorRtnVals)
|
|
TEST_CASE(8, TCDeferredColumns)
|
|
TEST_CASE(9, TCCommandAccessorTransactions)
|
|
TEST_CASE(10, TCRowsetAccessorTransactions)
|
|
TEST_CASE(11, TCExtendedErrors)
|
|
TEST_CASE(12, TCCrtRtnValsBeforeGetRows)
|
|
TEST_CASE(13, TCAddRefAccessor)
|
|
TEST_CASE(14, TCAccessorOnAlteredTable)
|
|
END_TEST_MODULE()
|
|
// }} TCW_TESTMODULE_END
|
|
|
|
|
|
HRESULT CAccessor::UseRowAccessorAndVerify(
|
|
HACCESSOR hAccessor, //@parm [IN] Handle of accessor
|
|
DBLENGTH cbRowSize, //@parm [IN] Size of buffer needed for row
|
|
ULONG ulRowNum, //@parm [IN] Row number needed for MakeData
|
|
DB_LORDINAL * rgColumnsOrd, //@parm [IN] Back end ordinals corresponding to rowset cols
|
|
DBCOUNTITEM cColumns, //@parm [IN] Number of ordinals in rgColumnsOrd array
|
|
DBBINDING * rgBinding, //@parm [IN] Array of bindings for this accessor
|
|
DBCOUNTITEM cBinding, //@parm [IN] Number of bindings in rgBinding array
|
|
BOOL fReadColumnsByRef, //@parm [IN] Whether or not accessor is READCOLUMNSBYREF
|
|
BOOL fKeepCurrentRows) //@parm [IN] TRUE indicates hRows are kept for next call,
|
|
// FALSE indicates that rows are not kept, and
|
|
// GetNextRows will be called next time to retrieve
|
|
// more rows.
|
|
{
|
|
BYTE * pData = NULL;
|
|
HROW * rgOnehRow = &m_hRow;
|
|
ULONG cRowSkip = 0;
|
|
IRowsetLocate * pIRowsetLocate = NULL;
|
|
DBBKMARK rgcbBookmarks[1]={0};
|
|
BYTE * rgpBookmarks[1]={NULL};
|
|
|
|
// Skip any rows before the one(s) we want to verify.
|
|
cRowSkip = ulRowNum-1;
|
|
|
|
m_hr = NOERROR;
|
|
m_cRowsObtained = 0;
|
|
|
|
//Allocate a new data buffer
|
|
pData = (BYTE *)m_pIMalloc->Alloc(cbRowSize);
|
|
if (!pData)
|
|
return ResultFromScode(E_OUTOFMEMORY);
|
|
|
|
memset(pData, 0, (size_t)cbRowSize);
|
|
|
|
//Get the data into our buffer
|
|
if (m_fIRowset)
|
|
{
|
|
//Only get new rows if user released them last time
|
|
if (!m_hRow)
|
|
{
|
|
//We could get DB_S_COMMANDREEXECUTED, so just expect success code
|
|
if (SUCCEEDED(m_pIRowset->RestartPosition(NULL)))
|
|
{
|
|
//Use IRowset to retrieve data
|
|
if (CHECK(m_hr = m_pIRowset->GetNextRows(NULL, cRowSkip, 1,
|
|
&m_cRowsObtained, (HROW **)&rgOnehRow), S_OK))
|
|
{
|
|
CHECK(m_hr = m_pIRowset->GetData(m_hRow, hAccessor, pData),S_OK);
|
|
}
|
|
else
|
|
{
|
|
//So we know that our hRow is no good
|
|
m_hRow = DB_NULL_HROW;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//Just get data on current row
|
|
m_hr = m_pIRowset->GetData(m_hRow, hAccessor, pData);
|
|
m_cRowsObtained = 1;
|
|
}
|
|
|
|
}
|
|
else
|
|
//Fail here since IRowset has to be there
|
|
return ResultFromScode(E_NOINTERFACE);
|
|
|
|
//Make sure we got the right number of rows, and GetData succeeded, if called
|
|
if (m_cRowsObtained && SUCCEEDED(m_hr))
|
|
{
|
|
//Make sure we have gotten back exactly one row.
|
|
COMPARE(m_cRowsObtained,1);
|
|
|
|
// Retrieve any bookmark value here because CompareData frees the BYREF bindngs
|
|
// and because provider-owned memory is freed at ReleaseRows time.
|
|
if (rgBinding && (rgBinding[0].iOrdinal == 0))
|
|
{
|
|
//We need length and value bound for the bookmark column
|
|
if ((rgBinding[0].dwPart & DBPART_LENGTH) &&
|
|
(rgBinding[0].dwPart & DBPART_VALUE))
|
|
{
|
|
|
|
//Retrieve the bookmark and its length from our row buffer
|
|
rgcbBookmarks[0] = *(LONG *)(pData+rgBinding[0].obLength);
|
|
if (rgBinding[0].wType & DBTYPE_BYREF)
|
|
{
|
|
// We have to allocate a buffer for the bookmark value
|
|
SAFE_ALLOC(rgpBookmarks[0], BYTE, rgcbBookmarks[0]);
|
|
memcpy(rgpBookmarks[0], (BYTE *)*(ULONG **)(pData+rgBinding[0].obValue), (size_t)rgcbBookmarks[0]);
|
|
}
|
|
else
|
|
rgpBookmarks[0] = (BYTE *)(pData+rgBinding[0].obValue);
|
|
}
|
|
|
|
//Check status if bound for the bookmark
|
|
if (rgBinding[0].dwPart & DBPART_STATUS)
|
|
{
|
|
COMPARE(*(ULONG *)(pData+rgBinding[0].obStatus), DBSTATUS_S_OK);
|
|
}
|
|
}
|
|
|
|
//Verify data value, length and status are what is expected
|
|
if (COMPARE(CompareData(cColumns, rgColumnsOrd, ulRowNum, pData, cBinding, rgBinding,
|
|
m_pTable, m_pIMalloc, PRIMARY), TRUE))
|
|
m_hr = NOERROR;
|
|
else
|
|
m_hr = E_FAIL;
|
|
|
|
//Clean up from row retrieval, if user doesn't want to keep the row
|
|
if (m_fIRowset && !fKeepCurrentRows)
|
|
{
|
|
CHECK(m_pIRowset->ReleaseRows(m_cRowsObtained,&m_hRow, NULL, NULL,NULL),S_OK);
|
|
m_hRow = DB_NULL_HROW;
|
|
}
|
|
|
|
//Test bookmark value -- we assume its in the first binding,
|
|
//otherwise we won't validate it. Note that if the accessor happens to be
|
|
// a NULL accessor here rgBinding can be NULL also. We skip this section
|
|
// if data validation above failed since likely the bookmark isn't valid.
|
|
if (rgpBookmarks[0] && m_hr == S_OK)
|
|
{
|
|
// We know we have a bookmark, but this doesn't require IRowsetLocate to be supported
|
|
// If it is we'll try it.
|
|
if (!VerifyInterface(m_pIRowset, IID_IRowsetLocate, ROWSET_INTERFACE,
|
|
(IUnknown **)&pIRowsetLocate))
|
|
{
|
|
// We don't report IRowsetLocate support, so we need to exit here with success
|
|
m_hr = S_OK;
|
|
goto CLEANUP;
|
|
}
|
|
|
|
//We'll get RowsNotReleased if we don't release this held row
|
|
//since we didn't specify CANHOLDROWS. We'll save the row
|
|
//we get from GetRowsByBookmark so the user still has one.
|
|
if (fKeepCurrentRows)
|
|
{
|
|
CHECK(m_pIRowset->ReleaseRows(m_cRowsObtained,&m_hRow, NULL, NULL,NULL),S_OK);
|
|
m_hRow = DB_NULL_HROW;
|
|
}
|
|
|
|
//Make sure we can get one row back with the bookmark
|
|
if (CHECK(m_hr = pIRowsetLocate->GetRowsByBookmark(NULL, 1,
|
|
rgcbBookmarks, (const BYTE **)rgpBookmarks, rgOnehRow, NULL),S_OK))
|
|
{
|
|
//Make sure data is from right row
|
|
CHECK(pIRowsetLocate->GetData(rgOnehRow[0], hAccessor, pData), S_OK);
|
|
COMPARE(CompareData(cColumns, rgColumnsOrd, ulRowNum, pData,
|
|
cBinding, rgBinding, m_pTable, m_pIMalloc, PRIMARY), TRUE);
|
|
|
|
//Keep this row so we can use it next time if the user has requested it
|
|
if (fKeepCurrentRows)
|
|
m_hRow = rgOnehRow[0];
|
|
else
|
|
CHECK(m_pIRowset->ReleaseRows(1, rgOnehRow, NULL, NULL,NULL),S_OK);
|
|
}
|
|
|
|
SAFE_RELEASE(pIRowsetLocate);
|
|
|
|
// For BYREF bookmarks we had to allocate a buffer to save the value
|
|
if (rgBinding[0].wType & DBTYPE_BYREF)
|
|
PROVIDER_FREE(rgpBookmarks[0]);
|
|
}
|
|
|
|
}
|
|
|
|
CLEANUP:
|
|
|
|
|
|
//Clean up fixed buffer
|
|
PROVIDER_FREE(pData);
|
|
|
|
//Set this to null so next time we will know row has been released
|
|
if (!fKeepCurrentRows)
|
|
m_hRow = DB_NULL_HROW;
|
|
|
|
//Results is either error on set up or results of CompareData()
|
|
return m_hr;
|
|
|
|
|
|
}
|
|
|
|
HRESULT CAccessor::UseParamAccessorAndVerify(
|
|
HACCESSOR hAccessor, //@parm [IN] Accessor to use
|
|
DBACCESSORFLAGS dwAccessorFlags, //@parm [IN] Accessor flags
|
|
DBLENGTH cbRowSize, //@parm [IN] Size for one row of parameter data
|
|
ULONG ulRowNum, //@parm [IN] Row number needed for MakeData
|
|
DBBINDING * rgBindings, //@parm [IN] Array of bindings for this accessor
|
|
DBCOUNTITEM cBindings, //@parm [IN] Number of bindings in rgBinding array)
|
|
ICommand * pICommand, //@parm [IN] Command to execute on.This must match accessor command object.
|
|
HRESULT hrExecute, //@parm [IN] Expected hresult from Execute call. Default S_OK.
|
|
BOOL fWarn) //@parm [IN] Whether warning or failure is issued. Default FALSE.
|
|
{
|
|
DBROWCOUNT cRowsAffected = 0;
|
|
ULONG iRow, cRows = 2;
|
|
IRowset * rgpRowset[2] = {NULL, NULL};
|
|
DBPARAMS Param;
|
|
BYTE * pData = NULL;
|
|
DBCOUNTITEM cBindingsFilled = 0;
|
|
|
|
m_hr = ResultFromScode(E_FAIL);
|
|
|
|
//Create a command that we will execute with parameters
|
|
TESTC_(m_hr = m_pTable->ExecuteCommand(SELECT_ALL_WITH_SEARCHABLE_AND_UPDATEABLE, IID_IUnknown,
|
|
NULL,NULL,NULL, NULL, EXECUTE_NEVER, 0, NULL,
|
|
NULL, NULL, &pICommand), S_OK);
|
|
|
|
//Alloc enough memory to hold a row of parameter data
|
|
pData = (BYTE *)m_pIMalloc->Alloc(cbRowSize);
|
|
|
|
if (!pData)
|
|
goto CLEANUP;
|
|
memset(pData, 0, (size_t)cbRowSize);
|
|
|
|
for (iRow = 0; iRow < cRows; iRow++)
|
|
{
|
|
|
|
//Set up parameter input values for selecting row 1
|
|
TESTC_(m_hr = FillInputBindings(m_pTable,
|
|
dwAccessorFlags, cBindings, rgBindings, &pData, ulRowNum,
|
|
m_cSearchableCols, m_rgSearchableCols, PRIMARY), S_OK);
|
|
|
|
cBindingsFilled = cBindings;
|
|
|
|
Param.cParamSets = 1;
|
|
Param.hAccessor = hAccessor;
|
|
Param.pData = pData;
|
|
|
|
m_hr = pICommand->Execute(NULL, IID_IRowset, &Param,
|
|
&cRowsAffected, (IUnknown **)&rgpRowset[iRow]);
|
|
|
|
//Determine which rowset interface is supported by this provider
|
|
//and ask for that interface on the execute
|
|
if (fWarn)
|
|
{
|
|
TESTW_(m_hr, hrExecute);
|
|
}
|
|
else
|
|
{
|
|
TESTC_(m_hr, hrExecute);
|
|
}
|
|
|
|
//Init this so only a successful row retrieval will set it back to S_OK
|
|
m_hr = ResultFromScode(E_FAIL);
|
|
|
|
if (rgpRowset[iRow])
|
|
{
|
|
// Use IRowset to get rows of data
|
|
|
|
HROW * rgOnehRow = (HROW *)m_pIMalloc->Alloc(sizeof(HROW));
|
|
|
|
if (!rgOnehRow)
|
|
{
|
|
m_hr = ResultFromScode(E_OUTOFMEMORY);
|
|
goto CLEANUP;
|
|
}
|
|
|
|
TESTC_(rgpRowset[iRow]->GetNextRows(NULL, 0, 1, &m_cRowsObtained,
|
|
(HROW **)&rgOnehRow),S_OK);
|
|
|
|
//One row should have been in rowset
|
|
if (COMPARE(m_cRowsObtained,1))
|
|
m_hr = NOERROR;
|
|
|
|
//CLEANUP
|
|
CHECK(rgpRowset[iRow]->ReleaseRows(1,rgOnehRow, NULL, NULL, NULL),S_OK);
|
|
|
|
PROVIDER_FREE(rgOnehRow);
|
|
}
|
|
|
|
// Release pData before we set it again.
|
|
ReleaseInputBindingsMemory(cBindingsFilled, rgBindings, pData);
|
|
cBindingsFilled = 0;
|
|
}
|
|
|
|
CLEANUP:
|
|
|
|
ReleaseInputBindingsMemory(cBindingsFilled, rgBindings, pData);
|
|
PROVIDER_FREE(pData);
|
|
SAFE_RELEASE(rgpRowset[0]);
|
|
SAFE_RELEASE(rgpRowset[1]);
|
|
|
|
//This should be S_OK if the parameterized query successfully brought back one row
|
|
return m_hr;
|
|
|
|
}
|
|
|
|
// Finds a combination of data types to match requirements for a particular
|
|
// variation
|
|
BOOL CAccessor::FindConversionTypes(
|
|
DBBINDING * prgBindings,
|
|
DBCOUNTITEM cBindings,
|
|
ULONG * piBackEnd,
|
|
DBTYPE * wOptType,
|
|
DBTYPE * wNonOptType)
|
|
{
|
|
IConvertType * pIConvertType=NULL;
|
|
IColumnsInfo * pIColumnsInfo=NULL;
|
|
DBORDINAL cColumns=0;
|
|
DBCOLUMNINFO * prgColumnInfo=NULL;
|
|
OLECHAR * pStringsBuffer=NULL;
|
|
ULONG iOpt, iNonOpt;
|
|
BOOL fFound=FALSE;
|
|
ULONG fNoBookmarks = 1;
|
|
|
|
// Get an IConvertType interface
|
|
if (!VerifyInterface(m_pIAccessor, IID_IConvertType,
|
|
ROWSET_INTERFACE, (IUnknown **)&pIConvertType))
|
|
return TEST_FAIL;
|
|
|
|
// Go through all the provider types
|
|
for (*piBackEnd=0; *piBackEnd < cBindings; (*piBackEnd)++)
|
|
{
|
|
for (iOpt=0; iOpt < cBindings; iOpt++)
|
|
{
|
|
if (S_OK == pIConvertType->CanConvert(prgBindings[*piBackEnd].wType,
|
|
prgBindings[iOpt].wType, DBCONVERTFLAGS_COLUMN))
|
|
{
|
|
for (iNonOpt=0; iNonOpt < cBindings; iNonOpt++)
|
|
{
|
|
/*
|
|
odtLog << L"Conversion from type: " << prgBindings[iOpt].wType <<
|
|
L" to type: " << prgBindings[iNonOpt].wType << L" is supported? " <<
|
|
(BOOL)(pIConvertType->CanConvert(prgBindings[iOpt].wType,
|
|
prgBindings[iNonOpt].wType, DBCONVERTFLAGS_COLUMN) == S_OK) << L"\n";
|
|
*/
|
|
|
|
if ((S_FALSE == pIConvertType->CanConvert(prgBindings[iOpt].wType,
|
|
prgBindings[iNonOpt].wType, DBCONVERTFLAGS_COLUMN)) &&
|
|
(prgBindings[*piBackEnd].wType == prgBindings[iNonOpt].wType))
|
|
/*
|
|
S_OK == pIConvertType->CanConvert(prgBindings[*piBackEnd].wType,
|
|
prgBindings[iNonOpt].wType, DBCONVERTFLAGS_COLUMN))
|
|
*/
|
|
{
|
|
*wNonOptType=prgBindings[iNonOpt].wType;
|
|
fFound=TRUE;
|
|
goto CLEANUP;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// None of the provider types worked, try DBTYPE_IUNKNOWN
|
|
|
|
// First see if it should be supported (provider supports DBPROP_OLEOBJECTS).
|
|
if (!m_fOLEOBJECTS)
|
|
goto CLEANUP;
|
|
|
|
// Now we need to get an IColumnsInfo interface so we can find a LONG column.
|
|
// It is provider specific whether non-LONG cols can be bound to IUNKNOWN, so
|
|
// don't count on it.
|
|
if (!VerifyInterface(m_pIAccessor,IID_IColumnsInfo,ROWSET_INTERFACE,
|
|
(IUnknown **)&pIColumnsInfo))
|
|
goto CLEANUP;
|
|
|
|
// Get the columns information
|
|
if (FAILED(pIColumnsInfo->GetColumnInfo(&cColumns, &prgColumnInfo, &pStringsBuffer)))
|
|
goto CLEANUP;
|
|
|
|
// See if bookmarks are available on the rowset
|
|
if (!prgColumnInfo[0].iOrdinal)
|
|
fNoBookmarks=0;
|
|
|
|
// Find a LONG BLOB column we can bind to IUNKNOWN
|
|
for (*piBackEnd=0; *piBackEnd < cBindings; (*piBackEnd)++)
|
|
{
|
|
if (prgColumnInfo[prgBindings[*piBackEnd].iOrdinal-fNoBookmarks].dwFlags & DBCOLUMNFLAGS_ISLONG &&
|
|
(prgBindings[*piBackEnd].wType == DBTYPE_STR ||
|
|
prgBindings[*piBackEnd].wType == DBTYPE_WSTR ||
|
|
prgBindings[*piBackEnd].wType == DBTYPE_BYTES))
|
|
{
|
|
// Can convert these to IUnknown
|
|
for (iOpt=0; iOpt < cBindings; iOpt++)
|
|
{
|
|
if ((prgBindings[iOpt].wType != DBTYPE_STR &&
|
|
prgBindings[iOpt].wType != DBTYPE_WSTR &&
|
|
prgBindings[iOpt].wType != DBTYPE_BYTES) &&
|
|
S_OK == pIConvertType->CanConvert(prgBindings[*piBackEnd].wType,
|
|
prgBindings[iOpt].wType, DBCONVERTFLAGS_COLUMN))
|
|
{
|
|
*wNonOptType=DBTYPE_IUNKNOWN;
|
|
fFound=TRUE;
|
|
goto CLEANUP;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
CLEANUP:
|
|
|
|
SAFE_RELEASE(pIConvertType);
|
|
SAFE_RELEASE(pIColumnsInfo);
|
|
PROVIDER_FREE(prgColumnInfo);
|
|
PROVIDER_FREE(pStringsBuffer);
|
|
|
|
if (fFound)
|
|
*wOptType=prgBindings[iOpt].wType;
|
|
|
|
return fFound;
|
|
}
|
|
|
|
|
|
//--------------------------------------------------------------------
|
|
// @mfunc Sets the first row of data in the table to the type indicated
|
|
// by eValue. Non updateable columns are skipped.
|
|
//
|
|
HRESULT TCDeferredColumns::SetData(EVALUE eValue)
|
|
{
|
|
HROW * rghRows = NULL;
|
|
DBCOUNTITEM cRowsObtained = 0;
|
|
CCol CurCol;
|
|
BYTE * pData = NULL;
|
|
WCHAR * wszData = NULL;
|
|
|
|
//In case we're at the end of the rowset, start from the beginning again
|
|
if (FAILED(m_hr = m_pSetIRowset->RestartPosition(NULL)))
|
|
goto CLEANUP;
|
|
|
|
//Get a row
|
|
if (!CHECK(m_hr = m_pSetIRowset->GetNextRows(NULL,0,1,&cRowsObtained,&rghRows), S_OK))
|
|
goto CLEANUP;
|
|
|
|
pData = (BYTE *)m_pIMalloc->Alloc(m_cbSetAllRowSize);
|
|
if (!pData)
|
|
{
|
|
m_hr = E_OUTOFMEMORY;
|
|
goto CLEANUP;
|
|
}
|
|
|
|
//Set data to eValue kind of data, for all updateable columns
|
|
if (!CHECK(m_hr = FillInputBindings(m_pTable,
|
|
DBACCESSOR_ROWDATA, m_cSetAllBindings, m_rgSetAllBindings, &pData,
|
|
g_uiRowNum, m_pTable->CountColumnsOnTable(), m_rgTableColOrds, eValue), S_OK))
|
|
goto CLEANUP;
|
|
|
|
//This assumes that non updatable cols will just be skipped in the SetData
|
|
if (SUCCEEDED(m_hr = m_pSetIRowsetChange->SetData(rghRows[0], m_SetAllAccessor, pData)))
|
|
//We consider any S hr ok with us
|
|
m_hr = NOERROR;
|
|
|
|
CLEANUP:
|
|
|
|
//Cleanup any out of line memory allocated in FillInputBindings
|
|
ReleaseInputBindingsMemory(m_cSetAllBindings, m_rgSetAllBindings, pData);
|
|
|
|
if (rghRows)
|
|
m_pSetIRowset->ReleaseRows(cRowsObtained, rghRows, NULL, NULL,NULL);
|
|
|
|
PROVIDER_FREE(rghRows);
|
|
PROVIDER_FREE(pData);
|
|
|
|
return m_hr;
|
|
|
|
}
|
|
|
|
// @mfunc Sets Deferred property if the fDeferred flag is set.
|
|
// Sets the fCacheDeferred flag for every column in rgBindings if
|
|
// the fCacheDeferred flag is set.
|
|
//
|
|
// NOTE: Returns E_FAIL if any of the requested the properties didn't set, else
|
|
// it returns S_OK. User should not specify a property which isn't supported
|
|
// as the method will return E_FAIL.
|
|
//
|
|
HRESULT TCDeferredColumns::SetDeferredProperties(
|
|
BOOL fDeferred, //Flag indicating if DEFERRED property is set
|
|
BOOL fCacheDeferred, //Flag indicating if CACHEDEFERRED property is set
|
|
DBCOUNTITEM cBindings, //Count of bindings in rgBindings. This is ignored if fCacheDeferred == FALSE.
|
|
DBBINDING * rgBindings //Bindings corresponding to columns for which CACHEDEFERRED
|
|
//is to be set. This is ignored if fCacheDeferred == FALSE.
|
|
)
|
|
{
|
|
|
|
DBPROPSET DBPropSet;
|
|
DBPROP * rgProps = NULL;
|
|
ULONG cProperties = 0;
|
|
ULONG cPropSets = 1; //This will be one, unless no properties are specified
|
|
|
|
//This is the max number of props we'll need, One for deferred, and
|
|
//one for each binding for cache deferred
|
|
rgProps = (DBPROP *)m_pIMalloc->Alloc((cBindings+1)*sizeof(DBPROP));
|
|
if (!rgProps)
|
|
return ResultFromScode(E_OUTOFMEMORY);
|
|
|
|
//Free the existing accessors and rowset, so we can start over
|
|
if (m_pIAccessor)
|
|
{
|
|
if (m_GetAllAccessor != DB_NULL_HACCESSOR)
|
|
{
|
|
m_pIAccessor->ReleaseAccessor(m_GetAllAccessor, NULL);
|
|
m_GetAllAccessor = DB_NULL_HACCESSOR;
|
|
}
|
|
|
|
if (m_VariableAccessor != DB_NULL_HACCESSOR)
|
|
{
|
|
m_pIAccessor->ReleaseAccessor(m_VariableAccessor, NULL);
|
|
m_VariableAccessor = DB_NULL_HACCESSOR;
|
|
}
|
|
|
|
if (m_FixedAccessor != DB_NULL_HACCESSOR)
|
|
{
|
|
m_pIAccessor->ReleaseAccessor(m_FixedAccessor, NULL);
|
|
m_FixedAccessor = DB_NULL_HACCESSOR;
|
|
}
|
|
}
|
|
|
|
if (m_pGetIRowset)
|
|
{
|
|
COMPARE(m_pGetIRowset->Release(), 1);
|
|
m_pGetIRowset = NULL;
|
|
}
|
|
ReleaseRowsetObject();
|
|
|
|
//Set up properties used on the CreateRowsetObject call
|
|
if (fDeferred)
|
|
{
|
|
//Set properties for Deferred
|
|
rgProps[cProperties].dwPropertyID = DBPROP_DEFERRED;
|
|
rgProps[cProperties].dwOptions = DBPROPOPTIONS_REQUIRED;
|
|
rgProps[cProperties].colid = DB_NULLID;
|
|
rgProps[cProperties].vValue.vt = VT_BOOL;
|
|
V_BOOL(&(rgProps[cProperties].vValue)) = VARIANT_TRUE;
|
|
//Set deferred for all cols, so we test every type
|
|
rgProps[cProperties].colid=DB_NULLID;
|
|
cProperties++;
|
|
}
|
|
if (fCacheDeferred)
|
|
{
|
|
//Set properties for CacheDeferred, for each column in the accessor
|
|
while (cBindings)
|
|
{
|
|
|
|
rgProps[cProperties].dwPropertyID = DBPROP_CACHEDEFERRED;
|
|
rgProps[cProperties].dwOptions = DBPROPOPTIONS_REQUIRED;
|
|
rgProps[cProperties].colid = DB_NULLID;
|
|
rgProps[cProperties].vValue.vt = VT_BOOL;
|
|
rgProps[cProperties].colid = m_rgDBIDs[(rgBindings[cBindings-1].iOrdinal)-1];
|
|
V_BOOL(&(rgProps[cProperties].vValue)) = VARIANT_TRUE;
|
|
cProperties++;
|
|
cBindings--;
|
|
}
|
|
}
|
|
|
|
if (cProperties)
|
|
{
|
|
cPropSets = 1;
|
|
|
|
//Set up Prop Set for our rowset properties
|
|
DBPropSet.guidPropertySet = DBPROPSET_ROWSET;
|
|
DBPropSet.cProperties = cProperties;
|
|
DBPropSet.rgProperties = rgProps;
|
|
|
|
}
|
|
else
|
|
//The SetRowsetProperties call will do nothing,
|
|
//since we have no properties
|
|
cPropSets = 0;
|
|
|
|
//Set the properties
|
|
SetRowsetProperties(&DBPropSet, cPropSets);
|
|
|
|
//Set m_pIAccessor on a 'select *' rowset with bookmarks
|
|
//We expect every property to be set, so check for S_OK
|
|
if (CHECK(m_hr = CreateRowsetObject(SELECT_VALIDATIONORDER), S_OK))
|
|
{
|
|
|
|
//If we get this far, we've already verified that IRowset is supported
|
|
if (VerifyInterface(m_pIAccessor,IID_IRowset,ROWSET_INTERFACE,
|
|
(IUnknown **)&m_pGetIRowset))
|
|
{
|
|
PROVIDER_FREE(m_rgFixedBindings);
|
|
|
|
if (CHECK(GetAccessorAndBindings(m_pIAccessor, DBACCESSOR_ROWDATA,
|
|
&m_FixedAccessor, &m_rgFixedBindings, &m_cFixedBindings, &m_cbFixedRowSize,
|
|
DBPART_LENGTH | DBPART_STATUS | DBPART_VALUE,
|
|
FIXED_LEN_COLS_BOUND, FORWARD, NO_COLS_BY_REF, NULL, NULL,
|
|
NULL, DBTYPE_EMPTY, 0, NULL, NULL,
|
|
NO_COLS_OWNED_BY_PROV, DBPARAMIO_NOTPARAM,
|
|
m_fBindLongCols),S_OK))
|
|
{
|
|
|
|
PROVIDER_FREE(m_rgVariableBindings);
|
|
|
|
if (CHECK(GetAccessorAndBindings(m_pIAccessor, DBACCESSOR_ROWDATA,
|
|
&m_VariableAccessor, &m_rgVariableBindings, &m_cVariableBindings, &m_cbVariableRowSize,
|
|
DBPART_LENGTH | DBPART_STATUS | DBPART_VALUE,
|
|
VARIABLE_LEN_COLS_BOUND,
|
|
FORWARD, NO_COLS_BY_REF, NULL, NULL,
|
|
NULL, DBTYPE_EMPTY, 0, NULL, NULL,
|
|
NO_COLS_OWNED_BY_PROV, DBPARAMIO_NOTPARAM,
|
|
m_fBindLongCols),S_OK))
|
|
{
|
|
|
|
PROVIDER_FREE(m_rgGetAllBindings);
|
|
|
|
if (CHECK(GetAccessorAndBindings(m_pIAccessor, DBACCESSOR_ROWDATA,
|
|
&m_GetAllAccessor, &m_rgGetAllBindings, &m_cGetAllBindings, &m_cbGetAllRowSize,
|
|
DBPART_LENGTH | DBPART_STATUS | DBPART_VALUE,
|
|
ALL_COLS_BOUND,
|
|
FORWARD, NO_COLS_BY_REF, NULL, NULL,
|
|
NULL, DBTYPE_EMPTY, 0, NULL, NULL,
|
|
NO_COLS_OWNED_BY_PROV, DBPARAMIO_NOTPARAM,
|
|
m_fBindLongCols),S_OK))
|
|
{
|
|
|
|
m_hr = NOERROR;
|
|
goto CLEANUP;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
//If we get here, we've fallen through and thus not totally succeeded
|
|
m_hr = ResultFromScode(E_FAIL);
|
|
|
|
CLEANUP:
|
|
PROVIDER_FREE(rgProps);
|
|
|
|
return m_hr;
|
|
}
|
|
|
|
|
|
// {{ TCW_TC_PROTOTYPE(TCCrtRtnValsAfterGetRows)
|
|
//*-----------------------------------------------------------------------
|
|
//| Test Case: TCCrtRtnValsAfterGetRows - Return values for all CreateAccessor error conditions
|
|
//| Created: 09/30/95
|
|
//*-----------------------------------------------------------------------
|
|
|
|
|
|
//--------------------------------------------------------------------
|
|
// @mfunc TestCase Initialization Routine
|
|
//
|
|
// @rdesc TRUE or FALSE
|
|
//
|
|
BOOL TCCrtRtnValsAfterGetRows::Init()
|
|
{
|
|
IColumnsInfo * pIColInfo = NULL;
|
|
ULONG cColumns = 0;
|
|
DBCOLUMNINFO * rgInfo = NULL;
|
|
WCHAR * pStrBuffer = NULL;
|
|
BOOL fResults = FALSE;
|
|
IRowsetInfo * pIRowsetInfo = NULL;
|
|
IOpenRowset * pIOpenRowset = NULL;
|
|
|
|
m_pCmdIAccessor = NULL;
|
|
|
|
// {{ TCW_INIT_BASECLASS_CHECK
|
|
if(CAccessor::Init())
|
|
// }}
|
|
{
|
|
// If m_fBindLongCols is set to BLOB_LONG in CAccessor::Init, then
|
|
// IRowsetLocate is supported on the rowset. Some providers require
|
|
// IRowsetLocate before BLOB columns can be retrieved via GetData.
|
|
if (m_fBindLongCols == BLOB_LONG)
|
|
SetRowsetProperties(m_pDBPropSetLocate, 1);
|
|
|
|
TESTC_(OpenRowsetObject(TRUE), S_OK);
|
|
|
|
if (!g_fCmdSupported)
|
|
odtLog << L"The provider does not appear to support commands.\n";
|
|
|
|
}
|
|
|
|
fResults = TRUE;
|
|
|
|
CLEANUP:
|
|
|
|
return fResults;
|
|
}
|
|
|
|
|
|
//--------------------------------------------------------------------
|
|
// @mfunc
|
|
//Tests creating the accessor given the data members as parameters,
|
|
//with the passed in status being expected.
|
|
//It is assumed that DB_E_ERRORSOCCURED is always the hr expected
|
|
//
|
|
// @rdesc TRUE or FALSE
|
|
//
|
|
|
|
HRESULT TCCrtRtnValsAfterGetRows::TestCommandAccessor(DBBINDSTATUS status, LONG lBinding, enum DEFER_MODE eDeferMode,
|
|
DBACCESSORFLAGS dwAccessorFlags)
|
|
{
|
|
|
|
// Save the value of m_hAccessor since it's used in VerifyError for the row accessor
|
|
// but needs to be populated with the command accessor handle for VerifyError below
|
|
HACCESSOR hCmdAccessor = DB_NULL_HACCESSOR;
|
|
BOOL fResults = FALSE;
|
|
ULONG cRef;
|
|
HRESULT hrExpect=S_OK;
|
|
|
|
//If we don't support a command, just return
|
|
if (!g_fCmdSupported)
|
|
{
|
|
fResults = TRUE;
|
|
return NOERROR;
|
|
}
|
|
|
|
// Get the command object ref count
|
|
m_pICommand->AddRef();
|
|
cRef = m_pICommand->Release();
|
|
|
|
CSetRowsetObject CommandRowsetObject((LPWSTR)gwszModuleName, m_pThisTestModule, m_pICommand, m_pTable);
|
|
|
|
// Tell the rowset object not to delete our table
|
|
CommandRowsetObject.SetTable(m_pTable, DELETETABLE_NO);
|
|
|
|
|
|
m_hr = m_pCmdIAccessor->CreateAccessor(dwAccessorFlags, m_cBindings,
|
|
m_rgBindings, m_cbRowSize, &hCmdAccessor, m_rgStatus);
|
|
|
|
if (eDeferMode == MUST_DEFERR)
|
|
{
|
|
HRESULT hr = E_FAIL;
|
|
|
|
switch (status)
|
|
{
|
|
case DBBINDSTATUS_NOINTERFACE:
|
|
hrExpect=E_NOINTERFACE;
|
|
break;
|
|
case DBBINDSTATUS_BADBINDINFO:
|
|
hrExpect=DB_E_BADBINDINFO;
|
|
break;
|
|
case DBBINDSTATUS_BADORDINAL:
|
|
hrExpect=DB_E_BADORDINAL;
|
|
break;
|
|
case DBBINDSTATUS_BADSTORAGEFLAGS:
|
|
hrExpect=DB_E_BADSTORAGEFLAGS;
|
|
break;
|
|
case DBBINDSTATUS_UNSUPPORTEDCONVERSION:
|
|
hrExpect=DB_E_UNSUPPORTEDCONVERSION;
|
|
break;
|
|
default:
|
|
ASSERT(!L"Unknown status for deferred validation.");
|
|
}
|
|
|
|
// Before we can attempt to use the accessor we need to open a rowset on the command
|
|
if (SUCCEEDED(hr = CommandRowsetObject.CreateRowsetObject(SELECT_VALIDATIONORDER)))
|
|
{
|
|
// Creating an accessor off the command object never validates against the metadata
|
|
fResults = VerifyError(CommandRowsetObject.m_pIAccessor, hCmdAccessor, hrExpect, DBBINDSTATUS_BADBINDINFO,
|
|
lBinding, m_rgBindings, MUST_DEFERR, MUST_FAIL);
|
|
}
|
|
else
|
|
{
|
|
fResults = CHECK(hr, hrExpect);
|
|
|
|
}
|
|
}
|
|
|
|
|
|
if (eDeferMode == IMMEDIATE)
|
|
// If the error condition can be detected without the metadata it must do so.
|
|
fResults = VerifyError(CommandRowsetObject.m_pIAccessor, hCmdAccessor, hrExpect, status,
|
|
lBinding, m_rgBindings, eDeferMode, MUST_FAIL);
|
|
|
|
CommandRowsetObject.ReleaseRowsetObject();
|
|
CommandRowsetObject.ReleaseCommandObject(cRef);
|
|
CommandRowsetObject.ReleaseDBSession();
|
|
|
|
if (hCmdAccessor)
|
|
CHECK(m_pCmdIAccessor->ReleaseAccessor(hCmdAccessor, &cRef), S_OK);
|
|
|
|
if (fResults)
|
|
return NOERROR;
|
|
else
|
|
return ResultFromScode(E_FAIL);
|
|
|
|
}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(1)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc E_INVALIDARG - Null phAccessor
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCCrtRtnValsAfterGetRows::Variation_1()
|
|
{
|
|
|
|
BOOL fResults = FALSE;
|
|
|
|
TESTC_(OpenRowsetObject(TRUE), S_OK);
|
|
|
|
//Null phAccessor should return invalid arg
|
|
fResults = CHECK(m_pIAccessor->CreateAccessor(DBACCESSOR_ROWDATA, m_cBindings,
|
|
m_rgBindings, 1, NULL, m_rgStatus), E_INVALIDARG);
|
|
|
|
if (g_fCmdSupported)
|
|
fResults &= CHECK(m_pCmdIAccessor->CreateAccessor(DBACCESSOR_ROWDATA, m_cBindings,
|
|
m_rgBindings, 1, NULL, m_rgStatus), E_INVALIDARG);
|
|
|
|
CLEANUP:
|
|
|
|
return (fResults) ? TEST_PASS : TEST_FAIL;
|
|
|
|
}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(2)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc DB_E_BADBINDINFO - Invalid dwPart
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCCrtRtnValsAfterGetRows::Variation_2()
|
|
{
|
|
BOOL fResults = FALSE;
|
|
|
|
TESTC_(OpenRowsetObject(TRUE), S_OK);
|
|
|
|
//Set first binding to invalid dwPart
|
|
m_rgBindings[0].dwPart = 0;
|
|
|
|
//Expect bad dwPart to cause an error
|
|
if (CHECK(m_pIAccessor->CreateAccessor(DBACCESSOR_ROWDATA, m_cBindings,
|
|
m_rgBindings, m_cbRowSize, &m_hAccessor, m_rgStatus), DB_E_ERRORSOCCURRED))
|
|
fResults = COMPARE(m_rgStatus[0], DBBINDSTATUS_BADBINDINFO);
|
|
|
|
//Try a command accessor as well
|
|
fResults &= CHECK(TestCommandAccessor(DBBINDSTATUS_BADBINDINFO, 0, IMMEDIATE, DBACCESSOR_ROWDATA), S_OK);
|
|
|
|
//Reset dwPart to valid value
|
|
m_rgBindings[0].dwPart = DBPART_VALUE | DBPART_LENGTH | DBPART_STATUS;
|
|
|
|
CLEANUP:
|
|
|
|
return (fResults) ? TEST_PASS : TEST_FAIL;
|
|
}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(3)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc DB_E_BADBINDINFO - wType is DBTYPE_EMPTY
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCCrtRtnValsAfterGetRows::Variation_3()
|
|
{
|
|
|
|
BOOL fResults = FALSE;
|
|
DBTYPE dbType;
|
|
|
|
TESTC_(OpenRowsetObject(TRUE), S_OK);
|
|
|
|
//Initialize accessor so we can verify it is set to NULL on error
|
|
m_hAccessor = (HACCESSOR)1;
|
|
|
|
//Remember valid value for first binding's wType
|
|
dbType = m_rgBindings[0].wType;
|
|
|
|
//Set first binding wType to DBTYPE_EMPTY
|
|
m_rgBindings[0].wType = DBTYPE_EMPTY;
|
|
|
|
//Expect wType of DBTYPE_EMPTY to cause an error
|
|
if (CHECK(m_pIAccessor->CreateAccessor(DBACCESSOR_ROWDATA, m_cBindings,
|
|
m_rgBindings, m_cbRowSize, &m_hAccessor, m_rgStatus), DB_E_ERRORSOCCURRED))
|
|
fResults = COMPARE(m_rgStatus[0], DBBINDSTATUS_BADBINDINFO);
|
|
|
|
//Try a command accessor as well
|
|
fResults &= CHECK(TestCommandAccessor(DBBINDSTATUS_BADBINDINFO, 0, IMMEDIATE, DBACCESSOR_ROWDATA), S_OK);
|
|
|
|
//Reset wType to previous value
|
|
m_rgBindings[0].wType = dbType;
|
|
|
|
CLEANUP:
|
|
|
|
return (fResults) ? TEST_PASS : TEST_FAIL;
|
|
|
|
}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(4)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc DB_E_BADBINDINFO - PASSBYREF without correct buffer format
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCCrtRtnValsAfterGetRows::Variation_4()
|
|
{
|
|
|
|
BOOL fResults = FALSE;
|
|
DBBYTEOFFSET obValue;
|
|
DBLENGTH cbMaxLen;
|
|
|
|
TESTC_(OpenRowsetObject(TRUE), S_OK);
|
|
|
|
//If we support PASSBYREF
|
|
if (m_fPassByRef)
|
|
{
|
|
//Remember the values we will be changing
|
|
obValue = m_rgBindings[0].obValue;
|
|
cbMaxLen = m_rgBindings[0].cbMaxLen;
|
|
|
|
//Ensure our buffer does not match the provider's by
|
|
//setting the cbMaxLen to 0 and the obValue to an offset of 1.
|
|
//A cbMaxLen of 0 should never occur for variable length data.
|
|
//In case of fixed length data, we use an obValue of 1, which is based
|
|
//on an assumption that no provider will skip one byte and then
|
|
//start the value buffer.
|
|
m_rgBindings[0].cbMaxLen = 0;
|
|
m_rgBindings[0].obValue = 1;
|
|
|
|
//Try PASSBYREF with bindings that don't match provider's buffer layout
|
|
m_hr =m_pIAccessor->CreateAccessor(DBACCESSOR_ROWDATA | DBACCESSOR_PASSBYREF,
|
|
m_cBindings, m_rgBindings, m_cbRowSize, &m_hAccessor, m_rgStatus);
|
|
|
|
//Verify return code -- should be immediate mode
|
|
fResults = VerifyError(m_pIAccessor, m_hAccessor, DB_E_BADBINDINFO, DBBINDSTATUS_BADBINDINFO,
|
|
0, m_rgBindings, IMMEDIATE, MUST_FAIL);
|
|
|
|
fResults &= SUCCEEDED(TestCommandAccessor(DBBINDSTATUS_BADBINDINFO, 0, MUST_DEFERR,
|
|
DBACCESSOR_ROWDATA | DBACCESSOR_PASSBYREF));
|
|
|
|
//Reset cbMaxLen and value offset to previous values
|
|
m_rgBindings[0].cbMaxLen = cbMaxLen;
|
|
m_rgBindings[0].obValue = obValue;
|
|
|
|
}
|
|
else
|
|
{
|
|
//We should fail right away since pass by ref isn't supported
|
|
//Try PASSBYREF with bindings that don't match provider's buffer layout
|
|
CHECKW(m_pIAccessor->CreateAccessor(DBACCESSOR_ROWDATA | DBACCESSOR_PASSBYREF,
|
|
m_cBindings, m_rgBindings, m_cbRowSize, &m_hAccessor, m_rgStatus),
|
|
DB_E_BYREFACCESSORNOTSUPPORTED);
|
|
fResults = TRUE;
|
|
}
|
|
|
|
CLEANUP:
|
|
SAFE_RELEASE_ACCESSOR(m_pIAccessor, m_hAccessor);
|
|
|
|
return (fResults) ? TEST_PASS : TEST_FAIL;
|
|
}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(5)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc DB_E_BADBINDINFO - DBMEMOWNER_PROVIDEROWNED with DBTYPE not matching provider's
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCCrtRtnValsAfterGetRows::Variation_5()
|
|
{
|
|
|
|
BOOL fResults = FALSE;
|
|
DBTYPE wType;
|
|
ULONG i=0;
|
|
|
|
TESTC_(OpenRowsetObject(TRUE), S_OK);
|
|
|
|
//Find a column which won't convert to IUnknown
|
|
for (i=0; i < m_cBindings; i++)
|
|
{
|
|
if (m_rgBindings[i].wType != DBTYPE_IUNKNOWN &&
|
|
m_rgBindings[i].wType != DBTYPE_IDISPATCH &&
|
|
m_rgBindings[i].wType != DBTYPE_BYTES &&
|
|
m_rgBindings[i].wType != DBTYPE_WSTR &&
|
|
m_rgBindings[i].wType != DBTYPE_STR)
|
|
break;
|
|
}
|
|
|
|
//Assume we have at least one non IUnknown convertable column, or we'll fail
|
|
if (i == m_cBindings)
|
|
{
|
|
odtLog << L"No IUnknown convertable column. \n";
|
|
return TEST_SKIPPED;
|
|
}
|
|
//Remember the wType which we will be changing
|
|
wType = m_rgBindings[i].wType;
|
|
|
|
//Use BYREF on the non IUnknown column's binding, and ensure our requested
|
|
//wType does not match the provider's by using DBTYPE_IUNKNOWN
|
|
m_rgBindings[i].wType = DBTYPE_BYREF | DBTYPE_IUNKNOWN;
|
|
|
|
//Make our bindings provider owned for the appropriate column
|
|
m_rgBindings[i].dwMemOwner = DBMEMOWNER_PROVIDEROWNED;
|
|
|
|
//Try DBMEMOWNER_PROVIDEROWNED with a binding type which doesn't match the provider's
|
|
m_hr =m_pIAccessor->CreateAccessor(DBACCESSOR_ROWDATA,
|
|
m_cBindings, m_rgBindings, m_cbRowSize, &m_hAccessor, m_rgStatus);
|
|
|
|
//Now move it back to client owned for next time
|
|
m_rgBindings[i].dwMemOwner = DBMEMOWNER_CLIENTOWNED;
|
|
|
|
//Verify return code -- should be immediate mode
|
|
fResults = VerifyError(m_pIAccessor, m_hAccessor, DB_E_BADBINDINFO, DBBINDSTATUS_BADBINDINFO,
|
|
i, m_rgBindings, MAY_DEFERR, MUST_FAIL);
|
|
|
|
//Reset correct type of binding we changed
|
|
m_rgBindings[i].wType = wType;
|
|
|
|
CLEANUP:
|
|
|
|
return (fResults) ? TEST_PASS : TEST_FAIL;
|
|
}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(6)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc DB_E_BADBINDINFO - PARAMETERDATA and Multiple Input bindings with same ordinal
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCCrtRtnValsAfterGetRows::Variation_6()
|
|
{
|
|
BOOL fResults = FALSE;
|
|
DBBINDING rgBindings[2];
|
|
|
|
//if parameter accessor is not supported, skip this variation
|
|
if(!g_fParamAccessor)
|
|
{
|
|
odtLog << wszParamAccesNotSupported;
|
|
return TEST_SKIPPED;
|
|
}
|
|
|
|
TESTC_(OpenRowsetObject(TRUE), S_OK);
|
|
|
|
//if the provider does not supported the command, skip this test.
|
|
if (!g_fCmdSupported)
|
|
{
|
|
odtLog << wszCommandNotSupported;
|
|
return TEST_SKIPPED;
|
|
}
|
|
//Build two identical bindings, so they'll have the same ordinal
|
|
//Don't use first binding, in case it's a bookmark
|
|
CopyBindings(&rgBindings[0],&m_rgBindings[1]);
|
|
CopyBindings(&rgBindings[1],&m_rgBindings[1]);
|
|
|
|
//Make sure the ParamIO type is INPUT
|
|
rgBindings[0].eParamIO = DBPARAMIO_INPUT;
|
|
rgBindings[1].eParamIO = DBPARAMIO_INPUT;
|
|
|
|
//Same ordinal for two input parameter bindings should cause error
|
|
if (CHECK(m_pCmdIAccessor->CreateAccessor(DBACCESSOR_PARAMETERDATA, 2,
|
|
rgBindings, m_cbRowSize, &m_hAccessor, m_rgStatus), DB_E_ERRORSOCCURRED))
|
|
fResults = COMPARE(m_rgStatus[1], DBBINDSTATUS_BADBINDINFO);
|
|
|
|
CLEANUP:
|
|
|
|
return (fResults) ? TEST_PASS : TEST_FAIL;
|
|
|
|
}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(7)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc DB_E_BADACCESSORFLAGS - PASSBYREF when DBPROP_BYREFACCESSORS is FALSE
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCCrtRtnValsAfterGetRows::Variation_7()
|
|
{
|
|
BOOL fResults = FALSE;
|
|
|
|
TESTC_(OpenRowsetObject(TRUE), S_OK);
|
|
|
|
m_hr = m_pIAccessor->CreateAccessor(DBACCESSOR_ROWDATA | DBACCESSOR_PASSBYREF, m_cBindings,
|
|
m_rgBindings, m_cbRowSize, &m_hAccessor, m_rgStatus);
|
|
|
|
//If we don't support this, we know what the return code should be
|
|
if (!m_fPassByRef)
|
|
CHECKW(m_hr, DB_E_BYREFACCESSORNOTSUPPORTED);
|
|
|
|
// If PASSBYREF is supported we don't know the binding layout.
|
|
// We might fail, or might have given the right layout by accident.
|
|
|
|
SAFE_RELEASE_ACCESSOR(m_pIAccessor, m_hAccessor);
|
|
|
|
//if the provider does not supported the command, skip this test.
|
|
if (g_fCmdSupported)
|
|
{
|
|
//Try command accessor as well
|
|
if (m_pICommand)
|
|
{
|
|
m_hr = m_pCmdIAccessor->CreateAccessor(DBACCESSOR_ROWDATA | DBACCESSOR_PASSBYREF, m_cBindings,
|
|
m_rgBindings, m_cbRowSize, &m_hAccessor, m_rgStatus);
|
|
|
|
//If we don't support this, we know what the return code should be
|
|
if (!m_fPassByRef)
|
|
CHECKW(m_hr, DB_E_BYREFACCESSORNOTSUPPORTED);
|
|
|
|
// If PASSBYREF is supported we don't know the binding layout.
|
|
// We might fail, or might have given the right layout by accident.
|
|
|
|
SAFE_RELEASE_ACCESSOR(m_pCmdIAccessor, m_hAccessor);
|
|
}
|
|
}
|
|
|
|
//Note that if we do support pass by ref, we'd still need to know the
|
|
//exact buffer format to get CreateAccessor to work correctly, and
|
|
//we don't know that info, so we can't verify anything in this case
|
|
|
|
fResults = TRUE;
|
|
|
|
CLEANUP:
|
|
|
|
return (fResults) ? TEST_PASS : TEST_FAIL;
|
|
}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(8)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc DB_E_BADBINDINFO - PARAMETERDATA with invalid eParamIO
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCCrtRtnValsAfterGetRows::Variation_8()
|
|
{
|
|
|
|
BOOL fResults = FALSE;
|
|
|
|
//if parameter accessor is not supported, skip this variation
|
|
if(!g_fParamAccessor)
|
|
{
|
|
odtLog << wszParamAccesNotSupported;
|
|
return TEST_SKIPPED;
|
|
}
|
|
|
|
//if the provider does not supported the command, skip this test.
|
|
if (!g_fCmdSupported)
|
|
{
|
|
odtLog << wszCommandNotSupported;
|
|
return TEST_SKIPPED;
|
|
}
|
|
|
|
TESTC_(OpenRowsetObject(TRUE), S_OK);
|
|
|
|
//Make sure all bindings are valid parameter bindings
|
|
SetParamIO(m_cBindings, m_rgBindings, DBPARAMIO_INPUT);
|
|
|
|
//Except for one: Change the first binding we'll use to DBPARAMIO_NOTPARAM
|
|
m_rgBindings[1].eParamIO = DBPARAMIO_NOTPARAM;
|
|
|
|
//Now try creating a parameter data accessor, this should fail immediately
|
|
//Make sure we skip the first binding in case it's a bookmark
|
|
if (CHECK(m_pCmdIAccessor->CreateAccessor(DBACCESSOR_PARAMETERDATA,
|
|
m_cBindings-1, &m_rgBindings[1], m_cbRowSize,
|
|
&m_hAccessor, m_rgStatus), DB_E_ERRORSOCCURRED))
|
|
fResults = COMPARE(m_rgStatus[0], DBBINDSTATUS_BADBINDINFO);
|
|
|
|
//Now switch back to normal rowdata for the rest of the variations
|
|
SetParamIO(m_cBindings, m_rgBindings, DBPARAMIO_NOTPARAM);
|
|
|
|
CLEANUP:
|
|
|
|
return (fResults) ? TEST_PASS : TEST_FAIL;
|
|
|
|
}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(9)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc DB_E_BADACCESSORFLAGS - OPTIMIZED created after GetNextRows
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCCrtRtnValsAfterGetRows::Variation_9()
|
|
{
|
|
HACCESSOR hOptAccessor = DB_NULL_HACCESSOR;
|
|
BOOL fResults = FALSE;
|
|
HRESULT hr;
|
|
DBBINDING * prgBindings = NULL;
|
|
|
|
TESTC_(OpenRowsetObject(TRUE), S_OK);
|
|
|
|
//Try to create an optimized accessor, should fail and set accessor to null
|
|
//Since we have gotten rows in the init function
|
|
if (SUCCEEDED(hr = m_pIAccessor->CreateAccessor(DBACCESSOR_ROWDATA | DBACCESSOR_OPTIMIZED,
|
|
m_cBindings, m_rgBindings, m_cbRowSize, &hOptAccessor, m_rgStatus)))
|
|
{
|
|
SAFE_RELEASE_ACCESSOR(m_pIAccessor, hOptAccessor);
|
|
odtLog << L"Warning: Creation of an optimized accessor AFTER rows have been retrieved succeeded.\n";
|
|
odtLog << L" This is usually only valid if the provider doesn't actually support optimized accessors.\n";
|
|
fResults = TRUE;
|
|
goto CLEANUP;
|
|
}
|
|
else
|
|
TESTC_(hr, DB_E_BADACCESSORFLAGS);
|
|
|
|
TESTC(NULL == hOptAccessor);
|
|
|
|
//if the provider does not supported the command, skip this test.
|
|
if (g_fCmdSupported)
|
|
{
|
|
//Command row data accessor should succeed since it is always before get next rows
|
|
//for the rowset which the accessor will be good for
|
|
TESTC_(m_pCmdIAccessor->CreateAccessor(DBACCESSOR_ROWDATA | DBACCESSOR_OPTIMIZED,
|
|
m_cBindings, m_rgBindings, m_cbRowSize, &hOptAccessor, m_rgStatus),
|
|
S_OK);
|
|
|
|
SAFE_RELEASE_ACCESSOR(m_pCmdIAccessor, hOptAccessor);
|
|
}
|
|
|
|
if(g_fParamAccessor)
|
|
{
|
|
//Make sure this is ignored for parameter data accessors
|
|
if (g_fCmdSupported)
|
|
{
|
|
DBCOUNTITEM cBindings=m_cBindings;
|
|
DBLENGTH cbRowSize=0;
|
|
|
|
// We need to fix up the bindings for a parameter accessor. Cannot bind ordinal 0, nor
|
|
// can any ordinal be larger than the number of bindings if the provider verifies the ordinal
|
|
// number isn't too large (not all providers do). Create a parameter binding array.
|
|
if (!(prgBindings = (DBBINDING *)PROVIDER_ALLOC(cBindings * sizeof(DBBINDING))))
|
|
{
|
|
odtLog << L"Out of memory.\n";
|
|
goto CLEANUP;
|
|
}
|
|
|
|
// Copy the binding information, but leave out the bookmark binding if it exists. Otherwise
|
|
// we can get DB_E_BADORDINAL on CreateAccessor.
|
|
if (m_rgBindings[0].iOrdinal == 0)
|
|
{
|
|
cBindings--;
|
|
memcpy(prgBindings, &m_rgBindings[1], (size_t)(cBindings * sizeof(DBBINDING)));
|
|
}
|
|
else
|
|
memcpy(prgBindings, m_rgBindings, (size_t)(cBindings * sizeof(DBBINDING)));
|
|
|
|
// Now go through the ordinals and make sure they're sequential in case a hole was left by
|
|
// a long column that wasn't bound. Otherwise we'll have a parameter ordinal larger than
|
|
// the number of bindings (DB_E_BADORDINAL).
|
|
for (ULONG iBind=0; iBind < cBindings; iBind++)
|
|
{
|
|
prgBindings[iBind].iOrdinal = iBind+1;
|
|
prgBindings[iBind].eParamIO = DBPARAMIO_INPUT;
|
|
cbRowSize+=prgBindings[iBind].cbMaxLen;
|
|
}
|
|
|
|
// We finally get to create the accessor
|
|
TESTC_(m_pCmdIAccessor->CreateAccessor(DBACCESSOR_PARAMETERDATA | DBACCESSOR_OPTIMIZED,
|
|
cBindings, prgBindings, cbRowSize, &hOptAccessor, m_rgStatus), S_OK);
|
|
|
|
}
|
|
}
|
|
|
|
fResults = TRUE;
|
|
|
|
CLEANUP:
|
|
|
|
PROVIDER_FREE(prgBindings);
|
|
SAFE_RELEASE_ACCESSOR(m_pCmdIAccessor, hOptAccessor);
|
|
|
|
return (fResults) ? TEST_PASS : TEST_FAIL;
|
|
|
|
}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(10)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc DB_E_BADBINDINFO - Second optimized accessor using same column
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCCrtRtnValsAfterGetRows::Variation_10()
|
|
{
|
|
|
|
BOOL fResults = FALSE;
|
|
HACCESSOR hOptAccessor = DB_NULL_HACCESSOR;
|
|
HRESULT hr;
|
|
|
|
// Open the rowset object and don't fetch rows first.
|
|
// Optimized accessors must be created before rows are fetched.
|
|
TESTC_(OpenRowsetObject(FALSE), S_OK);
|
|
|
|
//Create one optimized accessor
|
|
if (!CHECK(m_pIAccessor->CreateAccessor(DBACCESSOR_ROWDATA | DBACCESSOR_OPTIMIZED,
|
|
m_cBindings, m_rgBindings, m_cbRowSize, &hOptAccessor, m_rgStatus),
|
|
S_OK))
|
|
return TEST_FAIL;
|
|
|
|
|
|
//Now try to create a second optimized accessor with same first column number
|
|
//This should be detectable immediately. Note that some providers don't make
|
|
//any distinction between optimized and non-optimized, so this can succeed.
|
|
m_hr = m_pIAccessor->CreateAccessor(DBACCESSOR_ROWDATA | DBACCESSOR_OPTIMIZED,
|
|
1, m_rgBindings, m_cbRowSize, &m_hAccessor, m_rgStatus);
|
|
|
|
fResults = VerifyError(m_pIAccessor, m_hAccessor, DB_E_BADBINDINFO, DBBINDSTATUS_BADBINDINFO,
|
|
0, m_rgBindings, MAY_DEFERR, MAY_FAIL);
|
|
|
|
//Release the first optimized accessor
|
|
if (hOptAccessor && CHECK(m_pIAccessor->ReleaseAccessor(hOptAccessor, NULL),S_OK))
|
|
hOptAccessor = DB_NULL_HACCESSOR;
|
|
|
|
//Release the duplicate HACCESSOR if it was created anyway
|
|
if (m_hAccessor && CHECK(m_pIAccessor->ReleaseAccessor(m_hAccessor, NULL),S_OK))
|
|
m_hAccessor = DB_NULL_HACCESSOR;
|
|
|
|
//Now try the same thing on a command rowdata accessor
|
|
if (g_fCmdSupported)
|
|
{
|
|
//Create one optimized accessor
|
|
if (!CHECK(m_pCmdIAccessor->CreateAccessor(DBACCESSOR_ROWDATA | DBACCESSOR_OPTIMIZED,
|
|
m_cBindings, m_rgBindings, m_cbRowSize, &hOptAccessor, m_rgStatus),
|
|
S_OK))
|
|
return TEST_FAIL;
|
|
|
|
//Now try to create a second optimized accessor with same first column number
|
|
//This should be detectable immediately
|
|
m_hr = m_pCmdIAccessor->CreateAccessor(DBACCESSOR_ROWDATA | DBACCESSOR_OPTIMIZED,
|
|
1, m_rgBindings, m_cbRowSize, &m_hAccessor, m_rgStatus);
|
|
|
|
// Now we have to release and recreate the rowset object to make it pick up the new
|
|
// accessors from the command.
|
|
ReleaseRowsetObject();
|
|
hr=CreateRowsetObject(SELECT_VALIDATIONORDER);
|
|
|
|
if (!CHECK(hr,S_OK))
|
|
return TEST_FAIL;
|
|
|
|
//Verify return code -- should be immediate mode
|
|
fResults = VerifyError(m_pIAccessor, m_hAccessor, DB_E_BADBINDINFO, DBBINDSTATUS_BADBINDINFO,
|
|
0, m_rgBindings, MAY_DEFERR, MAY_FAIL);
|
|
|
|
//Release the first optimized accessor
|
|
if (hOptAccessor && CHECK(m_pCmdIAccessor->ReleaseAccessor(hOptAccessor, NULL),S_OK))
|
|
hOptAccessor = DB_NULL_HACCESSOR;
|
|
|
|
//Release the duplicate HACCESSOR if it was created anyway
|
|
if (m_hAccessor && CHECK(m_pCmdIAccessor->ReleaseAccessor(m_hAccessor, NULL),S_OK))
|
|
m_hAccessor = DB_NULL_HACCESSOR;
|
|
}
|
|
|
|
CLEANUP:
|
|
|
|
return (fResults) ? TEST_PASS : TEST_FAIL;
|
|
}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(11)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc DB_E_BADBINDINFO - Accessor with invalid coersion for column in existing optimized accessor
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCCrtRtnValsAfterGetRows::Variation_11()
|
|
{
|
|
BOOL fResults = FALSE;
|
|
HACCESSOR hOptAccessor = DB_NULL_HACCESSOR;
|
|
ULONG iBackEndType;
|
|
DBTYPE wType, wOptType, wNonOptType;
|
|
HRESULT hr;
|
|
BYTE * pData=NULL;
|
|
|
|
|
|
// Open the rowset object and don't fetch rows first.
|
|
// Optimized accessors must be created before rows are fetched.
|
|
TESTC_(OpenRowsetObject(FALSE), S_OK);
|
|
|
|
/*
|
|
Find binding indexes of bad types for this variation. We need:
|
|
1) Backend DBTYPE can convert to Optimized accessor DBTYPE
|
|
2) Backend DBTYPE can convert to NonOptimized accessor DBTYPE
|
|
3) Optimized accessor DBTYPE can't convert to NonOptimized accessor DBTYPE
|
|
|
|
This assumes the existing binding array has all columns bound to have all types
|
|
available.
|
|
*/
|
|
if (!FindConversionTypes(m_rgBindings, m_cBindings, &iBackEndType, &wOptType, &wNonOptType))
|
|
{
|
|
odtLog <<L"Can't find a combination of data types required for this variation.\n";
|
|
return TEST_SKIPPED;
|
|
}
|
|
|
|
//Remember value we'll be changing
|
|
wType = m_rgBindings[iBackEndType].wType;
|
|
|
|
// Set the dbtype to a valid conversion but one that can't convert.
|
|
m_rgBindings[iBackEndType].wType = wOptType;
|
|
|
|
//Create one optimized accessor with one non convertable column
|
|
if (!CHECK(m_pIAccessor->CreateAccessor(DBACCESSOR_ROWDATA | DBACCESSOR_OPTIMIZED,
|
|
1, &m_rgBindings[iBackEndType], m_cbRowSize, &hOptAccessor, m_rgStatus),
|
|
S_OK))
|
|
goto CLEANUP;
|
|
|
|
// Now change the type in the binding to other type.
|
|
m_rgBindings[iBackEndType].wType = wNonOptType;
|
|
|
|
// If we ended up with a DBTYPE_IUNKNOWN wNonOptType we need to set pObject
|
|
if (DBTYPE_IUNKNOWN == wNonOptType)
|
|
m_rgBindings[iBackEndType].pObject = &m_StorageObject;
|
|
|
|
//Now try to create a second accessor for same column,
|
|
//and use an unsupported coersion
|
|
m_hr = m_pIAccessor->CreateAccessor(DBACCESSOR_ROWDATA,
|
|
1, &m_rgBindings[iBackEndType], m_cbRowSize, &m_hAccessor, m_rgStatus);
|
|
|
|
//Verify return code -- may be deferred
|
|
fResults = VerifyError(m_pIAccessor, m_hAccessor, DB_E_BADBINDINFO, DBBINDSTATUS_BADBINDINFO,
|
|
0, &m_rgBindings[iBackEndType], MAY_DEFERR, MAY_FAIL);
|
|
|
|
|
|
//Release the first optimized accessor
|
|
if (hOptAccessor && CHECK(m_pIAccessor->ReleaseAccessor(hOptAccessor, NULL),S_OK))
|
|
hOptAccessor = DB_NULL_HACCESSOR;
|
|
|
|
//Release the duplicate HACCESSOR if it was created anyway
|
|
if (m_hAccessor && CHECK(m_pIAccessor->ReleaseAccessor(m_hAccessor, NULL),S_OK))
|
|
m_hAccessor = DB_NULL_HACCESSOR;
|
|
|
|
////////////////////////////////////////
|
|
//Now do same thing on command accessor
|
|
////////////////////////////////////////
|
|
if (g_fCmdSupported)
|
|
{
|
|
// Set DBTYPE back for optimized accessor
|
|
m_rgBindings[iBackEndType].wType = wOptType;
|
|
|
|
//Create optimized accessor
|
|
if (!CHECK(m_pCmdIAccessor->CreateAccessor(DBACCESSOR_ROWDATA | DBACCESSOR_OPTIMIZED,
|
|
1, &m_rgBindings[iBackEndType], m_cbRowSize, &hOptAccessor, m_rgStatus),
|
|
S_OK))
|
|
goto CLEANUP;
|
|
|
|
//Set to IUnknown for non-optimized accessor
|
|
m_rgBindings[iBackEndType].wType = wNonOptType;
|
|
|
|
//Now try to create a second accessor for same column,
|
|
//and use an unsupported coersion of DBTYPE_IUNKNOWN
|
|
m_hr = m_pCmdIAccessor->CreateAccessor(DBACCESSOR_ROWDATA,
|
|
1, &m_rgBindings[iBackEndType], m_cbRowSize, &m_hAccessor, m_rgStatus);
|
|
|
|
// The rowset opened in the init doesn't know anything about our command accessor
|
|
// so we must release and recreate it
|
|
ReleaseRowsetObject();
|
|
|
|
if (fResults &= CHECK(hr=CreateRowsetObject(SELECT_VALIDATIONORDER), S_OK))
|
|
// Verify return code -- MAY be deferred even though on command object since metadata not needed.
|
|
// VerifyError needs a pointer to a rowset interface to call GetNextRows and GetData.
|
|
// CreateRowsetObject places this interface in m_pIAccessor.
|
|
fResults &= VerifyError(m_pIAccessor, m_hAccessor, DB_E_BADBINDINFO, DBBINDSTATUS_BADBINDINFO,
|
|
0, &m_rgBindings[iBackEndType], MAY_DEFERR, MAY_FAIL);
|
|
|
|
//Release the first optimized accessor
|
|
if (hOptAccessor && CHECK(m_pCmdIAccessor->ReleaseAccessor(hOptAccessor, NULL),S_OK))
|
|
hOptAccessor = DB_NULL_HACCESSOR;
|
|
|
|
//Release the duplicate HACCESSOR if it was created anyway
|
|
if (m_hAccessor && CHECK(m_pCmdIAccessor->ReleaseAccessor(m_hAccessor, NULL),S_OK))
|
|
m_hAccessor = DB_NULL_HACCESSOR;
|
|
}
|
|
|
|
CLEANUP:
|
|
|
|
// Set the binding back to NULL
|
|
if (m_rgBindings)
|
|
m_rgBindings[iBackEndType].pObject = NULL;
|
|
|
|
return (fResults) ? TEST_PASS : TEST_FAIL;
|
|
}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(12)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc DB_E_BADORDINAL - iOrdinal of largest column number + 1
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCCrtRtnValsAfterGetRows::Variation_12()
|
|
{
|
|
|
|
BOOL fResults = FALSE;
|
|
DBORDINAL ulRememberOrdinal;
|
|
|
|
TESTC_(OpenRowsetObject(TRUE), S_OK);
|
|
|
|
//Set column number one too large
|
|
ulRememberOrdinal = m_rgBindings[0].iOrdinal;
|
|
//Number of possible columns plus 1 (for bookmark)
|
|
//plus 1 should be invalid
|
|
m_rgBindings[0].iOrdinal = m_pTable->CountColumnsOnTable()+2;
|
|
|
|
//Should be invalid column number
|
|
m_hr = m_pIAccessor->CreateAccessor(DBACCESSOR_ROWDATA,m_cBindings,
|
|
m_rgBindings, m_cbRowSize, &m_hAccessor, m_rgStatus);
|
|
|
|
//Verify return code
|
|
fResults = VerifyError(m_pIAccessor, m_hAccessor, DB_E_BADORDINAL, DBBINDSTATUS_BADORDINAL,
|
|
0, m_rgBindings, MAY_DEFERR, MUST_FAIL);
|
|
|
|
//Should be OK on Command object since they check no meta data there
|
|
if (g_fCmdSupported)
|
|
{
|
|
fResults &= CHECK(m_pCmdIAccessor->CreateAccessor(DBACCESSOR_ROWDATA,m_cBindings,
|
|
m_rgBindings, m_cbRowSize, &m_hAccessor, m_rgStatus), S_OK);
|
|
CHECK(m_pCmdIAccessor->ReleaseAccessor(m_hAccessor, NULL), S_OK);
|
|
m_hAccessor = DB_NULL_HACCESSOR;
|
|
}
|
|
|
|
//Set correct column number back
|
|
m_rgBindings[0].iOrdinal = ulRememberOrdinal;
|
|
|
|
CLEANUP:
|
|
|
|
return (fResults) ? TEST_PASS : TEST_FAIL;
|
|
|
|
}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(13)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc DB_E_BADORDINAL - iOrdinal of max value for ULONG
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCCrtRtnValsAfterGetRows::Variation_13()
|
|
{
|
|
BOOL fResults = FALSE;
|
|
ULONG ulMax;
|
|
DBORDINAL ulRememberOrdinal;
|
|
|
|
TESTC_(OpenRowsetObject(TRUE), S_OK);
|
|
|
|
//Get the max number a ULONG can hold
|
|
ulMax = (ULONG)pow(2.0, (double)sizeof(ULONG)*8) - 1;
|
|
|
|
//Set column number to max ULONG possible
|
|
ulRememberOrdinal = m_rgBindings[0].iOrdinal;
|
|
m_rgBindings[0].iOrdinal = ulMax;
|
|
|
|
//Max number the type can hold should be invalid column number
|
|
m_hr = m_pIAccessor->CreateAccessor(DBACCESSOR_ROWDATA, m_cBindings,
|
|
m_rgBindings, m_cbRowSize, &m_hAccessor, m_rgStatus);
|
|
|
|
//Verify return code
|
|
fResults = VerifyError(m_pIAccessor, m_hAccessor, DB_E_BADORDINAL, DBBINDSTATUS_BADORDINAL,
|
|
0, m_rgBindings, MAY_DEFERR, MUST_FAIL);
|
|
|
|
//Should be OK on Command object since they check no meta data there
|
|
if (g_fCmdSupported)
|
|
{
|
|
fResults &= CHECK(m_pCmdIAccessor->CreateAccessor(DBACCESSOR_ROWDATA,m_cBindings,
|
|
m_rgBindings, m_cbRowSize, &m_hAccessor, m_rgStatus), S_OK);
|
|
CHECK(m_pCmdIAccessor->ReleaseAccessor(m_hAccessor, NULL), S_OK);
|
|
m_hAccessor = DB_NULL_HACCESSOR;
|
|
}
|
|
|
|
//Set correct column number back
|
|
m_rgBindings[0].iOrdinal = ulRememberOrdinal;
|
|
|
|
CLEANUP:
|
|
|
|
return (fResults) ? TEST_PASS : TEST_FAIL;
|
|
|
|
}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(14)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc DB_E_BADBINDINFO - DBTYPE_BYREF with DBTYPE_EMPTY
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCCrtRtnValsAfterGetRows::Variation_14()
|
|
{
|
|
DBTYPE wType;
|
|
BOOL fResults = FALSE;
|
|
|
|
TESTC_(OpenRowsetObject(TRUE), S_OK);
|
|
|
|
//Remember wType we'll be changing
|
|
wType = m_rgBindings[0].wType;
|
|
|
|
//Try by ref with DBTYPE_EMPTY
|
|
m_rgBindings[0].wType = DBTYPE_BYREF | DBTYPE_EMPTY;
|
|
|
|
//Create should fail for this combination of dwTypes
|
|
//This error should be detectable immediately
|
|
m_hr = m_pIAccessor->CreateAccessor(DBACCESSOR_ROWDATA,
|
|
m_cBindings, m_rgBindings, m_cbRowSize, &m_hAccessor, m_rgStatus);
|
|
|
|
//Verify return code -- should be immediate mode
|
|
fResults = VerifyError(m_pIAccessor, m_hAccessor, DB_E_BADBINDINFO, DBBINDSTATUS_BADBINDINFO,
|
|
0, m_rgBindings, IMMEDIATE, MUST_FAIL);
|
|
|
|
//Test command accessor as well
|
|
fResults &= CHECK(TestCommandAccessor(DBBINDSTATUS_BADBINDINFO,0, IMMEDIATE, DBACCESSOR_ROWDATA), S_OK);
|
|
|
|
//Put our old wType back to what is was originally
|
|
m_rgBindings[0].wType = wType;
|
|
|
|
CLEANUP:
|
|
|
|
return (fResults) ? TEST_PASS : TEST_FAIL;
|
|
|
|
}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(15)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc DB_E_BADBINDINFO - DBTYPE_BYREF with DBTYPE_NULL
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCCrtRtnValsAfterGetRows::Variation_15()
|
|
{
|
|
DBTYPE wType;
|
|
BOOL fResults = FALSE;
|
|
|
|
TESTC_(OpenRowsetObject(TRUE), S_OK);
|
|
|
|
//Remember wType we'll be changing
|
|
wType = m_rgBindings[0].wType;
|
|
|
|
//Try by ref with DBTYPE_NULL
|
|
m_rgBindings[0].wType = DBTYPE_BYREF | DBTYPE_NULL;
|
|
|
|
//Create should fail for this combination of dwTypes
|
|
//This error should be detectable immediately
|
|
m_hr = m_pIAccessor->CreateAccessor(DBACCESSOR_ROWDATA,
|
|
m_cBindings, m_rgBindings, m_cbRowSize, &m_hAccessor, m_rgStatus);
|
|
|
|
//Verify return code -- should be immediate
|
|
fResults = VerifyError(m_pIAccessor, m_hAccessor, DB_E_BADBINDINFO, DBBINDSTATUS_BADBINDINFO,
|
|
0, m_rgBindings, IMMEDIATE, MUST_FAIL);
|
|
|
|
//Test command accessor as well
|
|
fResults &= CHECK(TestCommandAccessor(DBBINDSTATUS_BADBINDINFO,0, IMMEDIATE, DBACCESSOR_ROWDATA), S_OK);
|
|
|
|
//Put our old wType back to what is was originally
|
|
m_rgBindings[0].wType = wType;
|
|
|
|
CLEANUP:
|
|
|
|
return (fResults) ? TEST_PASS : TEST_FAIL;
|
|
|
|
}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(16)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc DB_E_BADBINDINFO - DBTYPE_BYREF with DBTYPE_RESERVED
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCCrtRtnValsAfterGetRows::Variation_16()
|
|
{
|
|
DBTYPE wType;
|
|
BOOL fResults = FALSE;
|
|
|
|
TESTC_(OpenRowsetObject(TRUE), S_OK);
|
|
|
|
//Remember wType we'll be changing
|
|
wType = m_rgBindings[0].wType;
|
|
|
|
//Try by ref with DBTYPE_RESERVED
|
|
m_rgBindings[0].wType = DBTYPE_BYREF | DBTYPE_RESERVED;
|
|
|
|
//Create should fail for this combination of dwTypes
|
|
m_hr = m_pIAccessor->CreateAccessor(DBACCESSOR_ROWDATA,
|
|
m_cBindings, m_rgBindings, m_cbRowSize, &m_hAccessor, m_rgStatus);
|
|
//Verify return code should be immediate
|
|
fResults = VerifyError(m_pIAccessor, m_hAccessor, DB_E_BADBINDINFO, DBBINDSTATUS_BADBINDINFO,
|
|
0, m_rgBindings, IMMEDIATE, MUST_FAIL);
|
|
|
|
//Test command accessor as well
|
|
fResults &= CHECK(TestCommandAccessor(DBBINDSTATUS_BADBINDINFO,0, IMMEDIATE, DBACCESSOR_ROWDATA), S_OK);
|
|
|
|
//Put our old wType back to what is was originally
|
|
m_rgBindings[0].wType = wType;
|
|
|
|
CLEANUP:
|
|
|
|
return (fResults) ? TEST_PASS : TEST_FAIL;
|
|
|
|
|
|
}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(17)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc DB_E_BADBINDINFO - DBTYPE_ARRAY | DBTYPE_BYREF
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCCrtRtnValsAfterGetRows::Variation_17()
|
|
{
|
|
DBTYPE wType;
|
|
BOOL fResults = FALSE;
|
|
|
|
TESTC_(OpenRowsetObject(TRUE), S_OK);
|
|
|
|
//Remember wType we'll be changing
|
|
wType = m_rgBindings[0].wType;
|
|
|
|
//Use mutually exclusive modifiers on simple type
|
|
m_rgBindings[0].wType = DBTYPE_BYREF | DBTYPE_ARRAY | DBTYPE_UI1;
|
|
|
|
//Create should fail for this combination of dwTypes
|
|
//This error should be detectable immediately
|
|
m_hr = m_pIAccessor->CreateAccessor(DBACCESSOR_ROWDATA,
|
|
m_cBindings, m_rgBindings, m_cbRowSize, &m_hAccessor, m_rgStatus);
|
|
//Verify return code -- should be immediate mode
|
|
fResults = VerifyError(m_pIAccessor, m_hAccessor, DB_E_BADBINDINFO, DBBINDSTATUS_BADBINDINFO,
|
|
0, m_rgBindings, IMMEDIATE, MUST_FAIL);
|
|
|
|
//Test command accessor as well
|
|
fResults &= CHECK(TestCommandAccessor(DBBINDSTATUS_BADBINDINFO,0, IMMEDIATE, DBACCESSOR_ROWDATA), S_OK);
|
|
|
|
//Put our old wType back to what is was originally
|
|
m_rgBindings[0].wType = wType;
|
|
|
|
CLEANUP:
|
|
|
|
return (fResults) ? TEST_PASS : TEST_FAIL;
|
|
|
|
}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(18)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc DB_E_BADBINDINFO - DBTYPE_ARRAY | DBTYPE_VECTOR
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCCrtRtnValsAfterGetRows::Variation_18()
|
|
{
|
|
DBTYPE wType;
|
|
BOOL fResults = FALSE;
|
|
|
|
TESTC_(OpenRowsetObject(TRUE), S_OK);
|
|
|
|
//Remember wType we'll be changing
|
|
wType = m_rgBindings[0].wType;
|
|
|
|
//Use mutually exclusive modifiers on simple type
|
|
m_rgBindings[0].wType = DBTYPE_VECTOR | DBTYPE_ARRAY | DBTYPE_UI1;
|
|
|
|
//Create should fail for this combination of dwTypes
|
|
//This error should be detectable immediately
|
|
m_hr = m_pIAccessor->CreateAccessor(DBACCESSOR_ROWDATA,
|
|
m_cBindings, m_rgBindings, m_cbRowSize, &m_hAccessor, m_rgStatus);
|
|
|
|
//Verify return code -- should be immediate mode
|
|
fResults = VerifyError(m_pIAccessor, m_hAccessor, DB_E_BADBINDINFO, DBBINDSTATUS_BADBINDINFO,
|
|
0, m_rgBindings, IMMEDIATE, MUST_FAIL);
|
|
|
|
//Test command accessor as well
|
|
fResults &= CHECK(TestCommandAccessor(DBBINDSTATUS_BADBINDINFO,0, IMMEDIATE, DBACCESSOR_ROWDATA), S_OK);
|
|
|
|
//Put our old wType back to what is was originally
|
|
m_rgBindings[0].wType = wType;
|
|
|
|
CLEANUP:
|
|
|
|
return (fResults) ? TEST_PASS : TEST_FAIL;
|
|
|
|
}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(19)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc DB_E_BADBINDINFO - DBTYPE_VECTOR | DBTYPE_BYREF
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCCrtRtnValsAfterGetRows::Variation_19()
|
|
{
|
|
DBTYPE wType;
|
|
BOOL fResults = FALSE;
|
|
|
|
TESTC_(OpenRowsetObject(TRUE), S_OK);
|
|
|
|
//Remember wType we'll be changing
|
|
wType = m_rgBindings[0].wType;
|
|
|
|
//Use mutually exclusive modifiers on simple type
|
|
m_rgBindings[0].wType = DBTYPE_BYREF | DBTYPE_VECTOR | DBTYPE_UI1;
|
|
|
|
//Create should fail for this combination of dwTypes
|
|
//This error should be detectable immediately
|
|
m_hr = m_pIAccessor->CreateAccessor(DBACCESSOR_ROWDATA,
|
|
m_cBindings, m_rgBindings, m_cbRowSize, &m_hAccessor, m_rgStatus);
|
|
|
|
//Verify return code -- should be immediate mode
|
|
fResults = VerifyError(m_pIAccessor, m_hAccessor, DB_E_BADBINDINFO, DBBINDSTATUS_BADBINDINFO,
|
|
0, m_rgBindings, IMMEDIATE, MUST_FAIL);
|
|
|
|
//Test command accessor as well
|
|
fResults &= CHECK(TestCommandAccessor(DBBINDSTATUS_BADBINDINFO,0, IMMEDIATE, DBACCESSOR_ROWDATA), S_OK);
|
|
|
|
//Put our old wType back to what is was originally
|
|
m_rgBindings[0].wType = wType;
|
|
|
|
CLEANUP:
|
|
|
|
return (fResults) ? TEST_PASS : TEST_FAIL;
|
|
}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(20)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc S_OK - PASSBYREF and DBMEMOWNER_PROVIDEROWNED
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCCrtRtnValsAfterGetRows::Variation_20()
|
|
{
|
|
//In this variation, we are testing if the DBMEMOWNER_PROVIDEROWNED is
|
|
//ignored when PASSBYREF is specified
|
|
|
|
BOOL fResults = FALSE;
|
|
|
|
TESTC_(OpenRowsetObject(TRUE), S_OK);
|
|
|
|
//Make all appropriate types bindings provider owned buffers
|
|
AdjustMemOwner(DBMEMOWNER_PROVIDEROWNED, m_cBindings, m_rgBindings);
|
|
|
|
m_hr =m_pIAccessor->CreateAccessor(
|
|
DBACCESSOR_ROWDATA | DBACCESSOR_PASSBYREF,
|
|
m_cBindings, m_rgBindings, m_cbRowSize, &m_hAccessor, m_rgStatus);
|
|
|
|
// Release the accessor in case it succeeds
|
|
SAFE_RELEASE_ACCESSOR(m_pIAccessor, m_hAccessor);
|
|
|
|
//We know what to expect if we don't support pass by ref accessors
|
|
if (!m_fPassByRef)
|
|
CHECKW(m_hr, DB_E_BYREFACCESSORNOTSUPPORTED);
|
|
|
|
//but we don't verify anything if we do support them, because
|
|
//we are still required to know the exact buffer layout to succeed and
|
|
//we don't have that info
|
|
|
|
//Do same thing for command accessor
|
|
if (g_fCmdSupported)
|
|
{
|
|
m_hr =m_pCmdIAccessor->CreateAccessor(
|
|
DBACCESSOR_ROWDATA | DBACCESSOR_PASSBYREF,
|
|
m_cBindings, m_rgBindings, m_cbRowSize, &m_hAccessor, m_rgStatus);
|
|
|
|
// Release the accessor in case it succeeds
|
|
SAFE_RELEASE_ACCESSOR(m_pCmdIAccessor, m_hAccessor);
|
|
|
|
//We know what to expect if we don't support pass by ref accessors
|
|
if (!m_fPassByRef)
|
|
CHECKW(m_hr, DB_E_BYREFACCESSORNOTSUPPORTED);
|
|
|
|
//but we don't verify anything if we do support them, because
|
|
//we are still required to know the exact buffer layout to succeed and
|
|
//we don't have that info
|
|
}
|
|
|
|
AdjustMemOwner(DBMEMOWNER_CLIENTOWNED, m_cBindings, m_rgBindings);
|
|
|
|
fResults = TRUE;
|
|
|
|
CLEANUP:
|
|
|
|
return (fResults) ? TEST_PASS : TEST_FAIL;
|
|
|
|
}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(21)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc DB_E_BADACCESSORFLAGS - Invalid DBACCESSORFLAGS
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCCrtRtnValsAfterGetRows::Variation_21()
|
|
{
|
|
DBACCESSORFLAGS dwAccessorFlags;
|
|
BOOL fResults = FALSE;
|
|
|
|
TESTC_(OpenRowsetObject(TRUE), S_OK);
|
|
|
|
if(!g_fParamAccessor)
|
|
{
|
|
//Set up bad value for dwAccessorFlags
|
|
dwAccessorFlags = (ULONG)~(DBACCESSOR_ROWDATA |
|
|
DBACCESSOR_OPTIMIZED | DBACCESSOR_PASSBYREF);
|
|
}
|
|
else
|
|
{
|
|
//Set up bad value for dwAccessorFlags
|
|
dwAccessorFlags = (ULONG)~(DBACCESSOR_ROWDATA | DBACCESSOR_PARAMETERDATA |
|
|
DBACCESSOR_OPTIMIZED | DBACCESSOR_PASSBYREF);
|
|
}
|
|
|
|
//Create should fail for bad DBACCESSORFLAGS - make sure rowdata is included
|
|
//so it gets passed the initial requirement of having the row or paramter bit set.
|
|
fResults = CHECK(m_pIAccessor->CreateAccessor(DBACCESSOR_ROWDATA | dwAccessorFlags,
|
|
m_cBindings, m_rgBindings, m_cbRowSize, &m_hAccessor, m_rgStatus), DB_E_BADACCESSORFLAGS);
|
|
|
|
if (g_fCmdSupported)
|
|
fResults &= CHECK(m_pCmdIAccessor->CreateAccessor(DBACCESSOR_ROWDATA | dwAccessorFlags,
|
|
m_cBindings, m_rgBindings, m_cbRowSize, &m_hAccessor, m_rgStatus), DB_E_BADACCESSORFLAGS);
|
|
|
|
CLEANUP:
|
|
|
|
return (fResults) ? TEST_PASS : TEST_FAIL;
|
|
|
|
}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(22)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc DB_E_BADORDINAL - iOrdinal = 0 for PARAMETERDATA accessor
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCCrtRtnValsAfterGetRows::Variation_22()
|
|
{
|
|
BOOL fResults = FALSE;
|
|
DBORDINAL iCol;
|
|
DBTYPE dbType;
|
|
|
|
//if parameter accessor is not supported, skip this variation
|
|
if(!g_fParamAccessor)
|
|
{
|
|
odtLog << wszParamAccesNotSupported;
|
|
return TEST_SKIPPED;
|
|
}
|
|
|
|
//Do this on a command object
|
|
if (!g_fCmdSupported)
|
|
{
|
|
odtLog << wszCommandNotSupported;
|
|
return TEST_SKIPPED;
|
|
}
|
|
|
|
TESTC_(OpenRowsetObject(TRUE), S_OK);
|
|
|
|
//Swap in column zero bound to string for first binding
|
|
iCol = m_rgBindings[0].iOrdinal;
|
|
dbType = m_rgBindings[0].wType;
|
|
m_rgBindings[0].iOrdinal = 0;
|
|
m_rgBindings[0].wType = DBTYPE_STR;
|
|
//Make sure it's valid parameter binding
|
|
SetParamIO(m_cBindings, m_rgBindings, DBPARAMIO_INPUT);
|
|
|
|
//Column zero should fail immediately
|
|
m_hr = m_pCmdIAccessor->CreateAccessor(DBACCESSOR_PARAMETERDATA,
|
|
m_cBindings, m_rgBindings, m_cbRowSize, &m_hAccessor, m_rgStatus);
|
|
|
|
//Verify return code -- should be immediate mode
|
|
fResults = VerifyError(m_pIAccessor, m_hAccessor, DB_E_BADORDINAL, DBBINDSTATUS_BADORDINAL,
|
|
0, m_rgBindings, IMMEDIATE, MUST_FAIL);
|
|
|
|
//Set bindings back the way they were
|
|
m_rgBindings[0].iOrdinal = iCol;
|
|
m_rgBindings[0].eParamIO = DBPARAMIO_NOTPARAM;
|
|
m_rgBindings[0].wType = dbType;
|
|
SetParamIO(m_cBindings, m_rgBindings, DBPARAMIO_NOTPARAM);
|
|
|
|
CLEANUP:
|
|
|
|
return (fResults) ? TEST_PASS : TEST_FAIL;
|
|
|
|
}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(23)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc DB_E_BADORDINAL - iOrdinal = 0 for ROWDATA accessor without bookmarks
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCCrtRtnValsAfterGetRows::Variation_23()
|
|
{
|
|
BOOL fResults = TRUE;
|
|
DBACCESSORFLAGS dwAccessorFlags;
|
|
DBORDINAL iCol;
|
|
DBTYPE dbType;
|
|
DBORDINAL cCols = 0;
|
|
IColumnsInfo * pIColInfo = NULL;
|
|
DBCOLUMNINFO * rgInfo = NULL;
|
|
WCHAR * pStrings = NULL;
|
|
BOOL fBkmkVisible = FALSE;
|
|
|
|
TESTC_(OpenRowsetObject(TRUE), S_OK);
|
|
|
|
//Find out if provider exposes column 0 itself before we go any farther
|
|
if (!VerifyInterface(m_pIAccessor, IID_IColumnsInfo,
|
|
ROWSET_INTERFACE, (IUnknown **)&pIColInfo))
|
|
return TEST_FAIL;
|
|
|
|
if (CHECK(pIColInfo->GetColumnInfo(&cCols, &rgInfo,
|
|
&pStrings), S_OK))
|
|
{
|
|
//Bookmark column exists on rowset
|
|
if (rgInfo[0].iOrdinal == 0)
|
|
fBkmkVisible = TRUE;
|
|
|
|
PROVIDER_FREE(rgInfo);
|
|
PROVIDER_FREE(pStrings);
|
|
SAFE_RELEASE(pIColInfo);
|
|
|
|
}
|
|
else
|
|
return TEST_FAIL;
|
|
|
|
//Set up parameter flags
|
|
dwAccessorFlags = DBACCESSOR_ROWDATA;
|
|
|
|
//Swap in column zero bound to bytes for first binding
|
|
iCol = m_rgBindings[0].iOrdinal;
|
|
dbType = m_rgBindings[0].wType;
|
|
m_rgBindings[0].iOrdinal = 0;
|
|
m_rgBindings[0].wType = DBTYPE_BYTES;
|
|
|
|
//Column zero is valid and should succeed
|
|
if (fBkmkVisible)
|
|
{
|
|
if (fResults &= CHECK(m_pIAccessor->CreateAccessor(dwAccessorFlags,
|
|
m_cBindings, m_rgBindings, m_cbRowSize,
|
|
&m_hAccessor, m_rgStatus), S_OK))
|
|
{
|
|
if (fResults &= CHECK(m_pIAccessor->ReleaseAccessor(m_hAccessor, NULL), S_OK))
|
|
m_hAccessor = DB_NULL_HACCESSOR;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//Column zero should fail as bookmark does not exist
|
|
m_hr = m_pIAccessor->CreateAccessor(dwAccessorFlags,
|
|
m_cBindings, m_rgBindings, m_cbRowSize, &m_hAccessor, m_rgStatus);
|
|
|
|
//Verify return code -- should be immediate mode
|
|
fResults = VerifyError(m_pIAccessor, m_hAccessor, DB_E_BADORDINAL, DBBINDSTATUS_BADORDINAL,
|
|
0, m_rgBindings, IMMEDIATE, MUST_FAIL);
|
|
}
|
|
|
|
//Now do accessor on command. Note that the command can't know for
|
|
//sure if a bookmark will exist on a rowset if IColumnsInfo doesn't
|
|
//report it, yet we should be able to bind that column because
|
|
//a bookmark could exist on the rowset later on
|
|
if (g_fCmdSupported)
|
|
if (CHECK(m_pCmdIAccessor->CreateAccessor(dwAccessorFlags,
|
|
m_cBindings, m_rgBindings, m_cbRowSize,
|
|
&m_hAccessor, m_rgStatus), S_OK))
|
|
{
|
|
fResults &= CHECK(m_pCmdIAccessor->ReleaseAccessor(m_hAccessor, NULL), S_OK);
|
|
m_hAccessor = DB_NULL_HACCESSOR;
|
|
}
|
|
|
|
|
|
//Set bindings back the way they were
|
|
m_rgBindings[0].iOrdinal = iCol;
|
|
m_rgBindings[0].wType = dbType;
|
|
|
|
|
|
CLEANUP:
|
|
|
|
return (fResults) ? TEST_PASS : TEST_FAIL;
|
|
|
|
}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(24)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc DB_E_BADBINDINFO - DBMEMOWNER_PROVIDEROWNED with PARAMETERDATA
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCCrtRtnValsAfterGetRows::Variation_24()
|
|
{
|
|
BOOL fResults = FALSE;
|
|
ULONG i;
|
|
HACCESSOR hAccessor = DB_NULL_HACCESSOR;
|
|
DBBINDING * rgNoBkMkBindings = NULL;
|
|
DBCOUNTITEM cNoBkMkBindings = 0;
|
|
DBLENGTH cbRowSize = 0;
|
|
|
|
//if parameter accessor is not supported, skip this variation
|
|
if(!g_fParamAccessor)
|
|
{
|
|
odtLog << wszParamAccesNotSupported;
|
|
return TEST_SKIPPED;
|
|
}
|
|
|
|
//Do this on a command object
|
|
if (!g_fCmdSupported)
|
|
{
|
|
odtLog << wszCommandNotSupported;
|
|
return TEST_SKIPPED;
|
|
}
|
|
|
|
TESTC_(OpenRowsetObject(FALSE), S_OK);
|
|
|
|
// We need the bindings bound BYREF for variable length cols
|
|
FREE_BINDINGS(&m_cBindings, &m_rgBindings);
|
|
|
|
TESTC_(GetAccessorAndBindings(m_pIAccessor,
|
|
DBACCESSOR_ROWDATA,
|
|
&m_hAccessor, &m_rgBindings, &m_cBindings, &m_cbRowSize,
|
|
DBPART_LENGTH | DBPART_STATUS | DBPART_VALUE,
|
|
ALL_COLS_BOUND, FORWARD, VARIABLE_LEN_COLS_BY_REF,
|
|
NULL, NULL, NULL, DBTYPE_EMPTY, 0, NULL, NULL,
|
|
NO_COLS_OWNED_BY_PROV, DBPARAMIO_INPUT, m_fBindLongCols), S_OK);
|
|
|
|
// Set our bindings to those returned above
|
|
rgNoBkMkBindings = m_rgBindings;
|
|
cNoBkMkBindings = m_cBindings;
|
|
cbRowSize = m_cbRowSize;
|
|
|
|
//Skip first binding if it is a bookmark binding
|
|
if (!m_rgBindings[0].iOrdinal)
|
|
{
|
|
rgNoBkMkBindings++;
|
|
cNoBkMkBindings--;
|
|
cbRowSize -= sizeof(DBSTATUS)+sizeof(DBLENGTH)+m_rgBindings[0].cbMaxLen;
|
|
}
|
|
|
|
//Make all appropriate types provider owned (this will find
|
|
//all the by ref cols we just created and change them to provider owned)
|
|
AdjustMemOwner(DBMEMOWNER_PROVIDEROWNED, cNoBkMkBindings, rgNoBkMkBindings);
|
|
|
|
//Make valid parameter bindings
|
|
SetParamIO(cNoBkMkBindings, rgNoBkMkBindings, DBPARAMIO_INPUT);
|
|
|
|
//Now try creating a parameter data accessor, this should fail immediately
|
|
if (CHECK(m_pCmdIAccessor->CreateAccessor(DBACCESSOR_PARAMETERDATA,
|
|
cNoBkMkBindings, rgNoBkMkBindings, cbRowSize,
|
|
&m_hAccessor, m_rgStatus), DB_E_ERRORSOCCURRED))
|
|
{
|
|
//Consider us passed, but COMPARE macro will still increment
|
|
//count for any problems we have
|
|
fResults = TRUE;
|
|
|
|
//For each each binding, check status (skipping first binding
|
|
//in case it is a bookmark column, which is not valid for
|
|
//parameterdata accessors and is tested by other variations).
|
|
for (i=0; i<cNoBkMkBindings; i++)
|
|
{
|
|
//For pointer types, we'be changed the memory ownership
|
|
if (rgNoBkMkBindings[i].wType & DBTYPE_BYREF ||
|
|
rgNoBkMkBindings[i].wType & DBTYPE_VECTOR ||
|
|
rgNoBkMkBindings[i].wType & DBTYPE_ARRAY ||
|
|
//Strip off a possible BYREF to check if its a BSTR
|
|
(~(DBTYPE_BYREF) & rgNoBkMkBindings[i].wType) == DBTYPE_BSTR)
|
|
|
|
fResults &= COMPARE(m_rgStatus[i], DBBINDSTATUS_BADBINDINFO);
|
|
else
|
|
//All the other columns' memory owners shouldn't
|
|
//have been changed, so should be OK
|
|
fResults &= COMPARE(m_rgStatus[i], DBBINDSTATUS_OK);
|
|
}
|
|
}
|
|
|
|
|
|
CLEANUP:
|
|
|
|
return (fResults) ? TEST_PASS : TEST_FAIL;
|
|
}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(25)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc S_OK - PARAMETERDATA and Multiple OUTPUT bindings with same ordinal
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCCrtRtnValsAfterGetRows::Variation_25()
|
|
{
|
|
HRESULT hrExpect=S_OK;
|
|
DBBINDSTATUS stExpect = DBBINDSTATUS_OK;
|
|
DBBINDING rgBindings[2];
|
|
ULONG iBind = 0;
|
|
|
|
//Do this on a command object
|
|
if (!g_fCmdSupported)
|
|
{
|
|
odtLog << wszCommandNotSupported;
|
|
return TEST_SKIPPED;
|
|
}
|
|
|
|
TESTC_(OpenRowsetObject(TRUE), S_OK);
|
|
|
|
//if parameter accessor is not supported, skip this variation
|
|
if(!g_fParamAccessor)
|
|
{
|
|
odtLog << wszParamAccesNotSupported;
|
|
hrExpect = DB_E_BADACCESSORFLAGS;
|
|
}
|
|
else if (!g_fOutputParam)
|
|
{
|
|
odtLog << L"This provider doesn't support output parameters\n";
|
|
hrExpect = DB_E_ERRORSOCCURRED;
|
|
stExpect = DBBINDSTATUS_BADBINDINFO;
|
|
}
|
|
|
|
// Parameter bindings with ordinal 0 are illegal.
|
|
if (m_rgBindings[iBind].iOrdinal == 0)
|
|
iBind = 1;
|
|
|
|
// We need at least one more binding slot
|
|
if (m_cBindings < iBind + 2)
|
|
{
|
|
odtLog << L"Not enough bindings to complete this variation.\n";
|
|
return TEST_SKIPPED;
|
|
}
|
|
|
|
//Build two identical bindings, so they'll have the same ordinal
|
|
//Don't use first binding in case it is a bookmark
|
|
CopyBindings(&rgBindings[0],&m_rgBindings[iBind]);
|
|
CopyBindings(&rgBindings[1],&m_rgBindings[iBind]);
|
|
|
|
|
|
// A consumer won't normally bind the same locations, so change them
|
|
// to the next available slot
|
|
rgBindings[1].obValue = m_rgBindings[iBind+1].obValue;
|
|
rgBindings[1].obLength = m_rgBindings[iBind+1].obLength;
|
|
rgBindings[1].obStatus = m_rgBindings[iBind+1].obStatus;
|
|
|
|
//Make sure the ParamIO type is OUTPUT
|
|
SetParamIO(2, rgBindings, DBPARAMIO_OUTPUT);
|
|
|
|
//Same ordinal for two output parameter bindings should be OK
|
|
if (CHECK(m_pCmdIAccessor->CreateAccessor(DBACCESSOR_PARAMETERDATA, 2,
|
|
rgBindings, m_cbRowSize, &m_hAccessor, m_rgStatus),
|
|
hrExpect))
|
|
{
|
|
// If we got the hresult we expect validate the status
|
|
if (hrExpect != DB_E_BADBINDINFO &&
|
|
COMPARE(m_rgStatus[0], stExpect) &&
|
|
COMPARE(m_rgStatus[1], stExpect))
|
|
return TEST_PASS; //Everything went as expected
|
|
|
|
}
|
|
|
|
CLEANUP:
|
|
|
|
return TEST_FAIL;
|
|
|
|
}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(26)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc DB_E_BADBINDINFO - wType is DBTYPE_NULL
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCCrtRtnValsAfterGetRows::Variation_26()
|
|
{
|
|
BOOL fResults = FALSE;
|
|
DBTYPE dbType;
|
|
|
|
TESTC_(OpenRowsetObject(TRUE), S_OK);
|
|
|
|
//Initialize accessor so we can verify it is set to NULL on error
|
|
m_hAccessor = (HACCESSOR)1;
|
|
|
|
//Remember valid value for first binding's wType
|
|
dbType = m_rgBindings[0].wType;
|
|
|
|
//Set first binding wType to DBTYPE_NULL
|
|
m_rgBindings[0].wType = DBTYPE_NULL;
|
|
|
|
//Expect wType of DBTYPE_NULL to cause an error immediately
|
|
m_hr = m_pIAccessor->CreateAccessor(DBACCESSOR_ROWDATA, m_cBindings,
|
|
m_rgBindings, m_cbRowSize, &m_hAccessor, m_rgStatus);
|
|
|
|
//Verify return code -- should be immediate mode
|
|
fResults = VerifyError(m_pIAccessor, m_hAccessor, DB_E_BADBINDINFO, DBBINDSTATUS_BADBINDINFO,
|
|
0, m_rgBindings, IMMEDIATE, MUST_FAIL);
|
|
|
|
fResults &=CHECK(TestCommandAccessor(DBBINDSTATUS_BADBINDINFO, 0, IMMEDIATE, DBACCESSOR_ROWDATA), S_OK);
|
|
|
|
//Reset wType to previous value
|
|
m_rgBindings[0].wType = dbType;
|
|
|
|
CLEANUP:
|
|
|
|
return (fResults) ? TEST_PASS : TEST_FAIL;
|
|
}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(27)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc E_INVALID - cBindings != 0 and rgBindings = NULL
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCCrtRtnValsAfterGetRows::Variation_27()
|
|
{
|
|
BOOL fResults = FALSE;
|
|
|
|
TESTC_(OpenRowsetObject(TRUE), S_OK);
|
|
|
|
fResults = CHECK(m_pIAccessor->CreateAccessor(DBACCESSOR_ROWDATA, 1,
|
|
NULL, m_cbRowSize, &m_hAccessor, m_rgStatus), E_INVALIDARG);
|
|
|
|
if (g_fCmdSupported)
|
|
fResults &= CHECK(m_pCmdIAccessor->CreateAccessor(DBACCESSOR_ROWDATA, 1,
|
|
NULL, m_cbRowSize, &m_hAccessor, m_rgStatus), E_INVALIDARG);
|
|
|
|
CLEANUP:
|
|
|
|
return (fResults) ? TEST_PASS : TEST_FAIL;
|
|
}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(28)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc DB_E_BADACCESSORFLAGS - dwAccessorFlags = OPTIMIZED only
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCCrtRtnValsAfterGetRows::Variation_28()
|
|
{
|
|
|
|
BOOL fResults = FALSE;
|
|
|
|
TESTC_(OpenRowsetObject(TRUE), S_OK);
|
|
|
|
fResults = CHECK(m_pIAccessor->CreateAccessor(DBACCESSOR_OPTIMIZED, m_cBindings,
|
|
m_rgBindings, m_cbRowSize, &m_hAccessor, m_rgStatus), DB_E_BADACCESSORFLAGS);
|
|
|
|
if (g_fCmdSupported)
|
|
fResults &= CHECK(m_pCmdIAccessor->CreateAccessor(DBACCESSOR_OPTIMIZED, m_cBindings,
|
|
m_rgBindings, m_cbRowSize, &m_hAccessor, m_rgStatus), DB_E_BADACCESSORFLAGS);
|
|
|
|
CLEANUP:
|
|
|
|
return (fResults) ? TEST_PASS : TEST_FAIL;
|
|
}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(29)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc DB_E_BADACCESSORFLAGS - dwAccessorFlags = INVALID only
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCCrtRtnValsAfterGetRows::Variation_29()
|
|
{
|
|
BOOL fResults = FALSE;
|
|
|
|
TESTC_(OpenRowsetObject(TRUE), S_OK);
|
|
|
|
fResults = CHECK(m_pIAccessor->CreateAccessor(DBACCESSOR_INVALID, m_cBindings,
|
|
m_rgBindings, m_cbRowSize, &m_hAccessor, m_rgStatus), DB_E_BADACCESSORFLAGS);
|
|
|
|
if (g_fCmdSupported)
|
|
fResults = CHECK(m_pCmdIAccessor->CreateAccessor(DBACCESSOR_INVALID, m_cBindings,
|
|
m_rgBindings, m_cbRowSize, &m_hAccessor, m_rgStatus), DB_E_BADACCESSORFLAGS);
|
|
|
|
CLEANUP:
|
|
|
|
return (fResults) ? TEST_PASS : TEST_FAIL;
|
|
}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(30)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc DB_E_NULLACCESSORNOTSUPPORTED - Null accessor created on Command Object
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCCrtRtnValsAfterGetRows::Variation_30()
|
|
{
|
|
|
|
BOOL fResults = FALSE;
|
|
|
|
//Do this on the command object
|
|
if (!g_fCmdSupported)
|
|
{
|
|
odtLog << wszCommandNotSupported;
|
|
return TEST_SKIPPED;
|
|
}
|
|
|
|
TESTC_(OpenRowsetObject(TRUE), S_OK);
|
|
|
|
//Null accessor shouldn't be allowed
|
|
fResults = CHECK(m_pCmdIAccessor->CreateAccessor(DBACCESSOR_ROWDATA, 0,
|
|
m_rgBindings, m_cbRowSize, &m_hAccessor, m_rgStatus),
|
|
DB_E_NULLACCESSORNOTSUPPORTED);
|
|
|
|
|
|
// Now create a non-null accessor so GetRowsAndData won't fail
|
|
CHECK(m_pIAccessor->CreateAccessor(DBACCESSOR_ROWDATA, m_cBindings,
|
|
m_rgBindings, m_cbRowSize, &m_hAccessor, m_rgStatus),
|
|
S_OK);
|
|
|
|
//Put our state back to having fetched rows for the rest
|
|
//of the variations.
|
|
CHECK(CreateRowsetObject(SELECT_VALIDATIONORDER), S_OK);
|
|
|
|
GetRowsAndData(m_pIAccessor, m_hAccessor, m_cbRowSize);
|
|
|
|
CLEANUP:
|
|
|
|
return (fResults) ? TEST_PASS : TEST_FAIL;
|
|
}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(31)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc PARAMETERDATA accessor on Rowset Object
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCCrtRtnValsAfterGetRows::Variation_31()
|
|
{
|
|
BOOL fResults = FALSE;
|
|
|
|
//if parameter accessor is not supported, skip this variation
|
|
if(!g_fParamAccessor)
|
|
{
|
|
odtLog << wszParamAccesNotSupported;
|
|
return TEST_PASS;
|
|
}
|
|
|
|
TESTC_(OpenRowsetObject(TRUE), S_OK);
|
|
|
|
//Make valid parameter bindings
|
|
SetParamIO(m_cBindings, m_rgBindings, DBPARAMIO_INPUT);
|
|
|
|
//Skip first binding in case it's a bookmark
|
|
fResults = CHECK(m_pIAccessor->CreateAccessor(DBACCESSOR_PARAMETERDATA, m_cBindings-1,
|
|
&m_rgBindings[1], m_cbRowSize, &m_hAccessor, m_rgStatus), DB_E_BADACCESSORFLAGS);
|
|
|
|
//Set back to rowdata bindings
|
|
SetParamIO(m_cBindings, m_rgBindings, DBPARAMIO_NOTPARAM);
|
|
|
|
CLEANUP:
|
|
|
|
return (fResults) ? TEST_PASS : TEST_FAIL;
|
|
}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(32)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc DB_E_ERRORSOCCURRED - PROVIDEROWNED dwMemOwner for non pointer types
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCCrtRtnValsAfterGetRows::Variation_32()
|
|
{
|
|
ULONG i;
|
|
BOOL fResults = FALSE;
|
|
|
|
TESTC_(OpenRowsetObject(TRUE), S_OK);
|
|
|
|
//Loop thru and make all bindings PROVIDER owned
|
|
for (i=0; i<m_cBindings; i++)
|
|
{
|
|
m_rgBindings[i].dwMemOwner = DBMEMOWNER_PROVIDEROWNED;
|
|
}
|
|
|
|
if (CHECK(m_pIAccessor->CreateAccessor(DBACCESSOR_ROWDATA, m_cBindings,
|
|
m_rgBindings, m_cbRowSize, &m_hAccessor, m_rgStatus), DB_E_ERRORSOCCURRED))
|
|
{
|
|
fResults = TRUE;
|
|
for (i=0; i<m_cBindings; i++)
|
|
{
|
|
//For pointer types, this is valid memory ownership
|
|
if (m_rgBindings[i].wType & DBTYPE_BYREF ||
|
|
m_rgBindings[i].wType & DBTYPE_VECTOR ||
|
|
m_rgBindings[i].wType & DBTYPE_ARRAY ||
|
|
//Strip off a possible BYREF to check if its a BSTR
|
|
(~(DBTYPE_BYREF) & m_rgBindings[i].wType) == DBTYPE_BSTR)
|
|
{
|
|
//Make sure status is OK
|
|
fResults &= COMPARE(m_rgStatus[i], DBBINDSTATUS_OK);
|
|
}
|
|
else //For any non pointer types, we expect an error
|
|
{
|
|
//Make sure status is BADBINDINFO
|
|
fResults &= COMPARE(m_rgStatus[i], DBBINDSTATUS_BADBINDINFO);
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
////////////////////////////////////////////
|
|
//Now do the same thing for command accessor
|
|
////////////////////////////////////////////
|
|
if (g_fCmdSupported)
|
|
if (CHECK(m_pCmdIAccessor->CreateAccessor(DBACCESSOR_ROWDATA, m_cBindings,
|
|
m_rgBindings, m_cbRowSize, &m_hAccessor, m_rgStatus), DB_E_ERRORSOCCURRED))
|
|
{
|
|
for (i=0; i<m_cBindings; i++)
|
|
{
|
|
//For pointer types, this is valid memory ownership
|
|
if (m_rgBindings[i].wType & DBTYPE_BYREF ||
|
|
m_rgBindings[i].wType & DBTYPE_VECTOR ||
|
|
m_rgBindings[i].wType & DBTYPE_ARRAY ||
|
|
//Strip off a possible BYREF to check if its a BSTR
|
|
(~(DBTYPE_BYREF) & m_rgBindings[i].wType) == DBTYPE_BSTR)
|
|
{
|
|
//Make sure status is OK
|
|
fResults &= COMPARE(m_rgStatus[i], DBBINDSTATUS_OK);
|
|
}
|
|
else //For any non pointer types, we expect an error
|
|
{
|
|
//Make sure status is BADBINDINFO
|
|
fResults &= COMPARE(m_rgStatus[i], DBBINDSTATUS_BADBINDINFO);
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
|
|
//Change back to CLIENT owned
|
|
for (i=0; i<m_cBindings; i++)
|
|
{
|
|
m_rgBindings[i].dwMemOwner = DBMEMOWNER_CLIENTOWNED;
|
|
}
|
|
|
|
CLEANUP:
|
|
|
|
return (fResults) ? TEST_PASS : TEST_FAIL;
|
|
}
|
|
|
|
|
|
// }}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(33)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc DB_E_BADBINDINFO - DBTYPE_IUnknown and NULL pObject
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCCrtRtnValsAfterGetRows::Variation_33()
|
|
{
|
|
|
|
TESTRESULT fResults = TEST_FAIL;
|
|
HACCESSOR hCmdAccessor = (HACCESSOR)ULONG_MAX;;
|
|
DBTYPE dbType = DBTYPE_EMPTY;
|
|
ULONG iCol;
|
|
CCol TempCol;
|
|
|
|
// If the provider doesn't support structured storage objects, then we'll skip this test
|
|
if (!m_fOLEOBJECTS)
|
|
{
|
|
odtLog << L"Provider doesn't support binding to structured storage objects.\n";
|
|
fResults = TEST_SKIPPED;
|
|
goto CLEANUP;
|
|
}
|
|
|
|
//Initialize accessor so we can verify it is set to NULL on error
|
|
m_hAccessor = (HACCESSOR)ULONG_MAX;
|
|
|
|
TESTC_(OpenRowsetObject(TRUE), S_OK);
|
|
|
|
// See if there's a column we can use with IUnknown
|
|
for (iCol=0; iCol < m_cBindings; iCol++)
|
|
{
|
|
// Can't get colinfo for bookmark
|
|
if (!m_rgBindings[iCol].iOrdinal)
|
|
continue;
|
|
|
|
// Retrieve colinfo for this column
|
|
CHECK(m_pTable->GetColInfo(m_rgBindings[iCol].iOrdinal, TempCol), S_OK);
|
|
|
|
// If this is a long column it should be usable with IUnknown binding
|
|
if (TempCol.GetIsLong())
|
|
break;
|
|
}
|
|
|
|
if (iCol == m_cBindings)
|
|
{
|
|
odtLog << L"Couldn't find a LONG column to try with DBTYPE_IUKNOWN.\n";
|
|
fResults = TEST_SKIPPED;
|
|
goto CLEANUP;
|
|
}
|
|
|
|
// Make sure the provider supports binding to IUnknown
|
|
|
|
//Remember valid value for long column's wType
|
|
dbType = m_rgBindings[iCol].wType;
|
|
|
|
//Set long column's binding wType to DBTYPE_IUNKNOWN
|
|
m_rgBindings[iCol].wType = DBTYPE_IUNKNOWN;
|
|
|
|
//Expect wType of DBTYPE_IUNKNOWN to cause an error
|
|
// Note: pObject is already NULL at this point
|
|
m_hr = m_pIAccessor->CreateAccessor(DBACCESSOR_ROWDATA, 1,
|
|
&m_rgBindings[iCol], m_cbRowSize, &m_hAccessor, m_rgStatus);
|
|
|
|
//Verify return code -- may be deferred
|
|
TESTC(VerifyError(m_pIAccessor, m_hAccessor, DB_E_BADBINDINFO, DBBINDSTATUS_BADBINDINFO,
|
|
0, &m_rgBindings[iCol], MAY_DEFERR, MAY_FAIL));
|
|
|
|
// Release the accessor now that we're done with it
|
|
if (m_hAccessor != ULONG_MAX && m_hAccessor != DB_NULL_HACCESSOR)
|
|
SAFE_RELEASE_ACCESSOR(m_pIAccessor, m_hAccessor);
|
|
|
|
//Initialize accessor so we can verify it is set to NULL on error
|
|
m_hAccessor = (HACCESSOR)ULONG_MAX;
|
|
|
|
// Try command accessor
|
|
if (m_pCmdIAccessor)
|
|
{
|
|
m_hr = m_pCmdIAccessor->CreateAccessor(DBACCESSOR_ROWDATA, 1,
|
|
&m_rgBindings[iCol], m_cbRowSize, &hCmdAccessor, m_rgStatus);
|
|
|
|
// Re-open rowset object to get command accessors inherited on the rowset.
|
|
// Note we CAUSED the error after getnextrows, but re-opening the rowset doesn't
|
|
// need to call GetNextRows again.
|
|
TESTC_(OpenRowsetObject(FALSE), S_OK);
|
|
|
|
// Reset binding back to IUnknown for comparison, since OpenRowset changes it back
|
|
m_rgBindings[iCol].wType = DBTYPE_IUNKNOWN;
|
|
|
|
// Validate
|
|
TESTC(VerifyError(m_pIAccessor, hCmdAccessor, DB_E_BADBINDINFO, DBBINDSTATUS_BADBINDINFO,
|
|
0, &m_rgBindings[iCol], MAY_DEFERR, MAY_FAIL));
|
|
}
|
|
|
|
fResults = TEST_PASS;
|
|
|
|
CLEANUP:
|
|
|
|
// Release the accessor now that we're done with it
|
|
if (m_hAccessor == ULONG_MAX)
|
|
m_hAccessor = DB_NULL_HACCESSOR;
|
|
else
|
|
SAFE_RELEASE_ACCESSOR(m_pIAccessor, m_hAccessor);
|
|
|
|
if (hCmdAccessor == ULONG_MAX)
|
|
hCmdAccessor = DB_NULL_HACCESSOR;
|
|
else
|
|
SAFE_RELEASE_ACCESSOR(m_pCmdIAccessor, hCmdAccessor);
|
|
|
|
//Reset wType to previous value
|
|
if (dbType != DBTYPE_EMPTY && m_rgBindings)
|
|
m_rgBindings[iCol].wType = dbType;
|
|
|
|
return fResults;
|
|
|
|
}
|
|
// }} TCW_VAR_PROTOTYPE_END
|
|
|
|
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(34)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc DB_E_BADBINDINFO: DBBINDFLAG_HTML for non-string type
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCCrtRtnValsAfterGetRows::Variation_34()
|
|
{
|
|
BOOL fSuccess = TEST_FAIL;
|
|
BOOL fNonStringType = FALSE;
|
|
ULONG iBind;
|
|
DBBINDSTATUS * pBindStatus = NULL;
|
|
enum FAILURE_MODE eFailMode = MUST_FAIL;
|
|
|
|
// Release any previous bindings or accessors
|
|
FREE_BINDINGS(&m_cBindings, &m_rgBindings);
|
|
SAFE_RELEASE_ACCESSOR(m_pIAccessor, m_hAccessor);
|
|
|
|
//Create Accessor with a binding using length, status and value
|
|
TESTC_(GetAccessorAndBindings(m_pIAccessor,
|
|
DBACCESSOR_ROWDATA,
|
|
&m_hAccessor, &m_rgBindings, &m_cBindings, &m_cbRowSize,
|
|
DBPART_LENGTH | DBPART_STATUS | DBPART_VALUE,
|
|
ALL_COLS_BOUND, FORWARD, NO_COLS_BY_REF, NULL,
|
|
NULL, NULL, DBTYPE_EMPTY, 0, NULL, g_rgParamOrds,
|
|
NO_COLS_OWNED_BY_PROV, DBPARAMIO_INPUT, m_fBindLongCols,
|
|
&pBindStatus),S_OK);
|
|
|
|
// Release the accessor we got above so we can change the binding information
|
|
SAFE_RELEASE_ACCESSOR(m_pIAccessor, m_hAccessor);
|
|
|
|
// Set dwFlags to DBBINDFLAG_HTML for all non-string types.
|
|
for(iBind = 0; iBind < m_cBindings; iBind++)
|
|
{
|
|
if (!IS_BASE_TYPE(m_rgBindings[iBind].wType, DBTYPE_STR) &&
|
|
!IS_BASE_TYPE(m_rgBindings[iBind].wType, DBTYPE_WSTR))
|
|
{
|
|
m_rgBindings[iBind].dwFlags = DBBINDFLAG_HTML;
|
|
fNonStringType = TRUE;
|
|
}
|
|
}
|
|
|
|
if (!fNonStringType)
|
|
{
|
|
odtLog << L"No non-string types available to test.\n";
|
|
fSuccess = TEST_SKIPPED;
|
|
goto CLEANUP;
|
|
}
|
|
|
|
// Now recreate the accessor. Note specifying DBBINDFLAGS_HTML is legal even if provider
|
|
// doesn't support it. It should be ignored.
|
|
m_hr = m_pIAccessor->CreateAccessor(DBACCESSOR_ROWDATA, m_cBindings, m_rgBindings, m_cbRowSize,
|
|
&m_hAccessor, m_rgStatus);
|
|
|
|
// Due to recent spec change need to force this as a warning if it succeeded
|
|
if (S_OK == m_hr)
|
|
{
|
|
CHECKW(m_hr, DB_E_ERRORSOCCURRED);
|
|
// Set failure mode to MAY_FAIL, which will then allow an S_OK on CreateAccessor
|
|
// to proceed and validate the data. For IMMEDIATE defer mode a failure will be
|
|
// posted if GetNextRows or GetData fail.
|
|
eFailMode = MAY_FAIL;
|
|
}
|
|
|
|
// The hr should be DB_E_ERRORSOCCURRED and all non-string types should have DBBINDSTATUS_BADBINDINFO
|
|
for(iBind = 0; iBind < m_cBindings; iBind++)
|
|
{
|
|
if (!IS_BASE_TYPE(m_rgBindings[iBind].wType, DBTYPE_STR) &&
|
|
!IS_BASE_TYPE(m_rgBindings[iBind].wType, DBTYPE_WSTR))
|
|
{
|
|
TESTC(VerifyError(m_pIAccessor, m_hAccessor, DB_E_BADBINDINFO, DBBINDSTATUS_BADBINDINFO,
|
|
iBind, m_rgBindings, IMMEDIATE, eFailMode));
|
|
}
|
|
}
|
|
|
|
fSuccess = TEST_PASS;
|
|
|
|
CLEANUP:
|
|
|
|
//Clean up
|
|
FREE_BINDINGS(&m_cBindings, &m_rgBindings);
|
|
SAFE_RELEASE_ACCESSOR(m_pIAccessor, m_hAccessor);
|
|
SAFE_FREE(pBindStatus)
|
|
|
|
return fSuccess;
|
|
}
|
|
// }} TCW_VAR_PROTOTYPE_END
|
|
|
|
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(35)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc DB_E_BADBINDINFO: dwFlags invalid
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCCrtRtnValsAfterGetRows::Variation_35()
|
|
{
|
|
BOOL fSuccess = TEST_FAIL;
|
|
ULONG iBind;
|
|
DBBINDSTATUS * pBindStatus = NULL;
|
|
enum FAILURE_MODE eFailMode = MUST_FAIL;
|
|
|
|
// Release any previous bindings or accessors
|
|
FREE_BINDINGS(&m_cBindings, &m_rgBindings);
|
|
SAFE_RELEASE_ACCESSOR(m_pIAccessor, m_hAccessor);
|
|
|
|
//Create Accessor with a binding using length, status and value
|
|
TESTC_(GetAccessorAndBindings(m_pIAccessor,
|
|
DBACCESSOR_ROWDATA,
|
|
&m_hAccessor, &m_rgBindings, &m_cBindings, &m_cbRowSize,
|
|
DBPART_LENGTH | DBPART_STATUS | DBPART_VALUE,
|
|
ALL_COLS_BOUND, FORWARD, NO_COLS_BY_REF, NULL,
|
|
NULL, NULL, DBTYPE_EMPTY, 0, NULL, g_rgParamOrds,
|
|
NO_COLS_OWNED_BY_PROV, DBPARAMIO_INPUT, m_fBindLongCols,
|
|
&pBindStatus),S_OK);
|
|
|
|
// Release the accessor we got above so we can change the binding information
|
|
SAFE_RELEASE_ACCESSOR(m_pIAccessor, m_hAccessor);
|
|
|
|
// Set dwFlags to an invalid value. This is any currently non-defined value
|
|
for(iBind = 0; iBind < m_cBindings; iBind++)
|
|
{
|
|
// Set all bits on
|
|
m_rgBindings[iBind].dwFlags = ULONG_MAX;
|
|
|
|
// DBBINDFLAGS_HTML is invalid for non-string types, so remove it to
|
|
// verify the provider checks the other flags.
|
|
if (!IS_BASE_TYPE(m_rgBindings[iBind].wType, DBTYPE_STR) &&
|
|
!IS_BASE_TYPE(m_rgBindings[iBind].wType, DBTYPE_WSTR))
|
|
m_rgBindings[iBind].dwFlags &= ~DBBINDFLAG_HTML;
|
|
}
|
|
|
|
// Now recreate the accessor. Note specifying DBBINDFLAG_HTML is legal even if provider
|
|
// doesn't support it. It should be ignored.
|
|
m_hr = m_pIAccessor->CreateAccessor(DBACCESSOR_ROWDATA, m_cBindings, m_rgBindings, m_cbRowSize,
|
|
&m_hAccessor, m_rgStatus);
|
|
|
|
// Due to recent spec change need to force this as a warning if it succeeded
|
|
if (S_OK == m_hr)
|
|
{
|
|
CHECKW(m_hr, DB_E_ERRORSOCCURRED);
|
|
// Set failure mode to MAY_FAIL, which will then allow an S_OK on CreateAccessor
|
|
// to proceed and validate the data. For IMMEDIATE defer mode a failure will be
|
|
// posted if GetNextRows or GetData fail.
|
|
eFailMode = MAY_FAIL;
|
|
}
|
|
|
|
// The hr should be DB_E_ERRORSOCCURRED and all types should have DBBINDSTATUS_BADBINDINFO
|
|
for(iBind = 0; iBind < m_cBindings; iBind++)
|
|
{
|
|
if (!VerifyError(m_pIAccessor, m_hAccessor, DB_E_BADBINDINFO, DBBINDSTATUS_BADBINDINFO,
|
|
iBind, m_rgBindings, IMMEDIATE, eFailMode))
|
|
goto CLEANUP;
|
|
}
|
|
|
|
fSuccess = TEST_PASS;
|
|
|
|
CLEANUP:
|
|
|
|
//Clean up
|
|
// Release any previous bindings or accessors
|
|
FREE_BINDINGS(&m_cBindings, &m_rgBindings);
|
|
SAFE_RELEASE_ACCESSOR(m_pIAccessor, m_hAccessor);
|
|
SAFE_FREE(pBindStatus)
|
|
|
|
return fSuccess;
|
|
}
|
|
// }} TCW_VAR_PROTOTYPE_END
|
|
|
|
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(36)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc DB_E_NULLACCESSORNOTSUPPORTED - Null accessor on rowset with IRowsetChange FALSE
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCCrtRtnValsAfterGetRows::Variation_36()
|
|
{
|
|
HACCESSOR hAccessor = DB_NULL_HACCESSOR;
|
|
BOOL fResults = FALSE;
|
|
IRowsetChange * pIRowsetChange = NULL;
|
|
HRESULT hr = E_FAIL;
|
|
|
|
// Make sure we don't have a rowset open
|
|
CleanUpRowsetObject();
|
|
|
|
TESTC_(SetProperty(DBPROP_IRowsetChange, DBPROPSET_ROWSET, &m_cPropSets, &m_rgPropSets,
|
|
DBTYPE_BOOL, (ULONG_PTR)VARIANT_FALSE), S_OK);
|
|
|
|
if (FAILED(hr = CreateRowsetObject(SELECT_VALIDATIONORDER)))
|
|
{
|
|
if (m_rgPropSets[0].rgProperties[0].dwStatus == DBPROPSTATUS_NOTSETTABLE ||
|
|
m_rgPropSets[0].rgProperties[0].dwStatus == DBPROPSTATUS_CONFLICTING)
|
|
{
|
|
CHECK(hr, DB_E_ERRORSOCCURRED);
|
|
odtLog << L"Unable to turn off IRowsetChange property.\n";
|
|
fResults = TEST_SKIPPED;
|
|
goto CLEANUP;
|
|
}
|
|
}
|
|
|
|
TESTC_(hr, S_OK);
|
|
|
|
// Make sure we did not get IRowsetChange property
|
|
TESTC(!VerifyInterface(m_pIAccessor,IID_IRowsetChange, ROWSET_INTERFACE,
|
|
(IUnknown **)&pIRowsetChange));
|
|
|
|
// Should return error
|
|
fResults = CHECKW(m_pIAccessor->CreateAccessor(DBACCESSOR_ROWDATA, 0,
|
|
m_rgBindings, 1, &hAccessor, m_rgStatus), DB_E_NULLACCESSORNOTSUPPORTED);
|
|
|
|
CLEANUP:
|
|
|
|
SAFE_RELEASE_ACCESSOR(m_pIAccessor, hAccessor);
|
|
SAFE_RELEASE(pIRowsetChange);
|
|
FreeProperties(&m_cPropSets, &m_rgPropSets);
|
|
CHECK(SetProperty(DBPROP_IRowsetChange, DBPROPSET_ROWSET, &m_cPropSets, &m_rgPropSets,
|
|
DBTYPE_BOOL, (ULONG_PTR) VARIANT_FALSE, DBPROPOPTIONS_OPTIONAL), S_OK);
|
|
|
|
return (fResults);
|
|
|
|
}
|
|
// }} TCW_VAR_PROTOTYPE_END
|
|
|
|
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(37)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc DB_E_BADBINDINFO: dwMemOwner invalid
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCCrtRtnValsAfterGetRows::Variation_37()
|
|
{
|
|
BOOL fSuccess = TEST_FAIL;
|
|
ULONG iBind;
|
|
DBBINDSTATUS * pBindStatus = NULL;
|
|
enum FAILURE_MODE eFailMode = MUST_FAIL;
|
|
|
|
// Release any previous object to prevent mem leak.
|
|
CleanUpRowsetObject();
|
|
|
|
TESTC_(OpenRowsetObject(TRUE), S_OK);
|
|
|
|
//Create Accessor with a binding using length, status and value
|
|
TESTC_(GetAccessorAndBindings(m_pIAccessor,
|
|
DBACCESSOR_ROWDATA,
|
|
&m_hAccessor, &m_rgBindings, &m_cBindings, &m_cbRowSize,
|
|
DBPART_LENGTH | DBPART_STATUS | DBPART_VALUE,
|
|
ALL_COLS_BOUND, FORWARD, NO_COLS_BY_REF, NULL,
|
|
NULL, NULL, DBTYPE_EMPTY, 0, NULL, g_rgParamOrds,
|
|
NO_COLS_OWNED_BY_PROV, DBPARAMIO_INPUT, m_fBindLongCols,
|
|
&pBindStatus),S_OK);
|
|
|
|
// Release the accessor we got above so we can change the binding information
|
|
SAFE_RELEASE_ACCESSOR(m_pIAccessor, m_hAccessor);
|
|
|
|
// Set dwFlags to an invalid value. This is any currently non-defined value
|
|
for(iBind = 0; iBind < m_cBindings; iBind++)
|
|
// Set all bits on except PROVIDEROWNED (CLIENTOWNED is 0!)
|
|
m_rgBindings[iBind].dwMemOwner = ULONG_MAX & ~DBMEMOWNER_PROVIDEROWNED;
|
|
|
|
// Now recreate the accessor with the invalid dwMemOwner
|
|
m_hr = m_pIAccessor->CreateAccessor(DBACCESSOR_ROWDATA, m_cBindings, m_rgBindings, m_cbRowSize,
|
|
&m_hAccessor, m_rgStatus);
|
|
|
|
// Due to recent spec change need to force this as a warning if it succeeded
|
|
if (S_OK == m_hr)
|
|
{
|
|
CHECKW(m_hr, DB_E_ERRORSOCCURRED);
|
|
// Set failure mode to MAY_FAIL, which will then allow an S_OK on CreateAccessor
|
|
// to proceed and validate the data. For IMMEDIATE defer mode a failure will be
|
|
// posted if GetNextRows or GetData fail.
|
|
eFailMode = MAY_FAIL;
|
|
}
|
|
|
|
// The hr should be DB_E_ERRORSOCCURRED and all types should have DBBINDSTATUS_BADBINDINFO
|
|
for(iBind = 0; iBind < m_cBindings; iBind++)
|
|
{
|
|
if (!VerifyError(m_pIAccessor, m_hAccessor, DB_E_BADBINDINFO, DBBINDSTATUS_BADBINDINFO,
|
|
iBind, m_rgBindings, IMMEDIATE, eFailMode))
|
|
goto CLEANUP;
|
|
}
|
|
|
|
fSuccess = TEST_PASS;
|
|
|
|
CLEANUP:
|
|
|
|
//Clean up
|
|
// Release any previous bindings or accessors
|
|
FREE_BINDINGS(&m_cBindings, &m_rgBindings);
|
|
SAFE_RELEASE_ACCESSOR(m_pIAccessor, m_hAccessor);
|
|
SAFE_FREE(pBindStatus)
|
|
|
|
return fSuccess;
|
|
}
|
|
// }} TCW_VAR_PROTOTYPE_END
|
|
|
|
|
|
// {{ TCW_TERMINATE_METHOD
|
|
//--------------------------------------------------------------------
|
|
// @mfunc TestCase Termination Routine
|
|
//
|
|
// @rdesc TRUE or FALSE
|
|
//
|
|
BOOL TCCrtRtnValsAfterGetRows::Terminate()
|
|
{
|
|
CleanUpRowsetObject();
|
|
|
|
return(CAccessor::Terminate());
|
|
}
|
|
// }}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_TC_PROTOTYPE(TCCreateValidRowAccessors)
|
|
//*-----------------------------------------------------------------------
|
|
//| Test Case: TCCreateValidRowAccessors - Creation of valid row accessors
|
|
//| Created: 10/20/95
|
|
//*-----------------------------------------------------------------------
|
|
|
|
//--------------------------------------------------------------------
|
|
// @mfunc TestCase Initialization Routine
|
|
//
|
|
// @rdesc TRUE or FALSE
|
|
//
|
|
BOOL TCCreateValidRowAccessors::Init()
|
|
{
|
|
DBCOLUMNINFO * rgInfo = NULL;
|
|
WCHAR * pStrBuffer = NULL;
|
|
ULONG cColumns = 0;
|
|
IColumnsInfo * pIColInfo = NULL;
|
|
const ULONG cProps = 2;
|
|
HRESULT hr;
|
|
BOOL fPropsSettable=FALSE;
|
|
|
|
m_pDBPropSet = (DBPROPSET *)PROVIDER_ALLOC(sizeof(DBPROPSET));
|
|
m_prgDBProps = (DBPROP *)PROVIDER_ALLOC(sizeof(DBPROP) * cProps);
|
|
|
|
if (!m_pDBPropSet || !m_prgDBProps)
|
|
{
|
|
odtLog << wszMemoryAllocationError;
|
|
return FALSE;
|
|
}
|
|
|
|
m_prgDBProps[0].dwPropertyID = DBPROP_IRowsetChange;
|
|
m_prgDBProps[0].dwOptions = DBPROPOPTIONS_REQUIRED;
|
|
m_prgDBProps[0].colid = DB_NULLID;
|
|
m_prgDBProps[0].vValue.vt = VT_BOOL;
|
|
V_BOOL(&(m_prgDBProps[0].vValue)) = VARIANT_TRUE;
|
|
|
|
m_prgDBProps[1].dwPropertyID = DBPROP_UPDATABILITY;
|
|
m_prgDBProps[1].dwOptions = DBPROPOPTIONS_REQUIRED;
|
|
m_prgDBProps[1].colid = DB_NULLID;
|
|
m_prgDBProps[1].vValue.vt = VT_I4;
|
|
m_prgDBProps[1].vValue.lVal = DBPROPVAL_UP_INSERT | DBPROPVAL_UP_DELETE;
|
|
|
|
m_pDBPropSet->guidPropertySet = DBPROPSET_ROWSET;
|
|
m_pDBPropSet->cProperties = cProps;
|
|
m_pDBPropSet->rgProperties = m_prgDBProps;
|
|
|
|
// {{ TCW_INIT_BASECLASS_CHECK
|
|
if(CAccessor::Init())
|
|
// }}
|
|
{
|
|
fPropsSettable=SettableProperty(DBPROP_IRowsetChange, DBPROPSET_ROWSET, (IUnknown *)m_pThisTestModule->m_pIUnknown, DATASOURCE_INTERFACE) &
|
|
SettableProperty(DBPROP_UPDATABILITY, DBPROPSET_ROWSET, (IUnknown *)m_pThisTestModule->m_pIUnknown, DATASOURCE_INTERFACE);
|
|
|
|
if (fPropsSettable)
|
|
SetRowsetProperties(m_pDBPropSet, 1);
|
|
|
|
//Set m_pIAccessor on a rowset created with 'select *' rowset. We'll
|
|
//use this interface ptr to do our tests.
|
|
hr=CreateRowsetObject(SELECT_VALIDATIONORDER);
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
if(SUCCEEDED(VerifyRowsetProperties((IUnknown *)m_pIAccessor, m_pDBPropSet, 1)))
|
|
m_fPropertiesSet = TRUE;
|
|
else
|
|
m_fPropertiesSet = FALSE;
|
|
}
|
|
|
|
if (CheckHr(hr))
|
|
{
|
|
//Try to get an IRowset interface
|
|
if(VerifyInterface(m_pIAccessor,IID_IRowset, ROWSET_INTERFACE,
|
|
(IUnknown **)&m_pIRowset))
|
|
{
|
|
//Record that IRowset is supported
|
|
m_fIRowset = TRUE;
|
|
//We got IRowset, that's all we need
|
|
return TRUE;
|
|
}
|
|
|
|
}
|
|
//since we want to test the row accessor, it is okay if we can not set these properties.
|
|
//the only drawback is that we have to skip var1.
|
|
else if(hr==DB_E_ERRORSOCCURRED)
|
|
{
|
|
// Release the properties which will affect opening rowset later
|
|
if (m_rgPropSets)
|
|
{
|
|
// Walk Set array, freeing all member property arrays
|
|
for(ULONG i=0; i<m_cPropSets; i++)
|
|
{
|
|
PROVIDER_FREE(m_rgPropSets[i].rgProperties);
|
|
}
|
|
|
|
PROVIDER_FREE(m_rgPropSets);
|
|
m_cPropSets = 0;
|
|
}
|
|
|
|
hr=CreateRowsetObject(SELECT_VALIDATIONORDER);
|
|
|
|
if(hr==S_OK)
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(1)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc Null Accessor
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCCreateValidRowAccessors::Variation_1()
|
|
{
|
|
BOOL fSuccess = TRUE;
|
|
HRESULT hr=S_OK;
|
|
HRESULT hrExp = NOERROR;
|
|
HROW rghRows[1]={DB_NULL_HROW};
|
|
DBROWSTATUS rgRowStatus[1];
|
|
|
|
if(!m_fPropertiesSet)
|
|
hr= E_NOINTERFACE;
|
|
|
|
//If IRowsetChange is not supported, NULL accessor is not supported.
|
|
if(!VerifyInterface(m_pIAccessor,IID_IRowsetChange, ROWSET_INTERFACE,
|
|
(IUnknown **)&m_pIRowsetChange))
|
|
{
|
|
odtLog <<L"Provider does not support IRowsetChange.\n";
|
|
hrExp = DB_E_NULLACCESSORNOTSUPPORTED;
|
|
|
|
if (S_OK == m_pIAccessor->QueryInterface(IID_IRowsetChange, (void **)&m_pIRowsetChange))
|
|
{
|
|
// We're not supposed to use this interface, but it's actually supported. Therefore creating
|
|
// a NULL accessor should actually succeed. Since this is not a proper condition for testing
|
|
// skip this variation.
|
|
SAFE_RELEASE(m_pIRowsetChange);
|
|
return TEST_SKIPPED;
|
|
}
|
|
}
|
|
|
|
|
|
//Pass cBindings = 0 to create a NULL accessor, m_rgBindings is null
|
|
//and should be ignored
|
|
fSuccess &= CHECK(hr = m_pIAccessor->CreateAccessor(DBACCESSOR_ROWDATA, 0, m_rgBindings,
|
|
m_cbRowSize, &m_hAccessor, m_rgStatus),hrExp);
|
|
|
|
if(hr==S_OK && m_pIRowsetChange)
|
|
{
|
|
//Try to use NULL Accessor, this may fail if nulls and defaults
|
|
//are not available for a column, which is perfectly valid, so don't
|
|
//check return code.
|
|
|
|
// Note: This can also fail if a NULL in the key column results in a duplicate primary key.
|
|
hr=m_pIRowsetChange->InsertRow(NULL,m_hAccessor,NULL, &rghRows[0]);
|
|
|
|
//GetBindings should return same values we've used to create the accessor
|
|
fSuccess &= VerifyBindings(m_pIAccessor, m_rgBindings, 0, m_hAccessor, DBACCESSOR_ROWDATA);
|
|
|
|
// Accessor creation was successful and we're done with it.
|
|
fSuccess &= CHECK(m_pIAccessor->ReleaseAccessor(m_hAccessor, NULL), S_OK);
|
|
m_hAccessor = DB_NULL_HACCESSOR;
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
// Let the table object know how many rows it's got
|
|
m_pTable->AddRow();
|
|
|
|
// TODO: Verify the proper row was added
|
|
|
|
// Remove row we've just added
|
|
|
|
// We can fail to delete the row when using default values because the provider
|
|
// may not always know which row is referenced by the row handle. The provider
|
|
// may not actually know the default values, especially with Query Based Udates
|
|
hr = m_pIRowsetChange->DeleteRows(NULL, 1, rghRows, rgRowStatus);
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
m_pTable->SubtractRow();
|
|
fSuccess &= CHECK(hr, S_OK);
|
|
fSuccess &= COMPARE(rgRowStatus[0], DBROWSTATUS_S_OK);
|
|
}
|
|
else
|
|
{
|
|
// If we didn't delete the row using the row handle above we might have stumbled
|
|
// over the QBU limitation, so don't fail for that, but check for proper error
|
|
// and status.
|
|
fSuccess &= CHECK(hr, DB_E_ERRORSOCCURRED);
|
|
fSuccess &= COMPARE(rgRowStatus[0], DBROWSTATUS_E_NEWLYINSERTED);
|
|
|
|
// Remove row by deleting all rows and re-adding one
|
|
|
|
// We can't depend on commands being available here, so delete all the
|
|
// rows using IRowsetChange. We need the new row in our rowset so we
|
|
// have to close and re-open the rowset object.
|
|
fSuccess &= CHECK(m_pIRowset->ReleaseRows(1, rghRows, NULL, NULL, NULL), S_OK);
|
|
rghRows[0] = DB_NULL_HROW;
|
|
SAFE_RELEASE(m_pIRowsetChange);
|
|
SAFE_RELEASE(m_pIRowset);
|
|
ReleaseRowsetObject();
|
|
|
|
SetRowsetProperties(m_pDBPropSet, 1);
|
|
|
|
if (!(fSuccess &= CHECK(CreateRowsetObject(USE_OPENROWSET), S_OK)))
|
|
goto CLEANUP;
|
|
|
|
if(!(fSuccess &= VerifyInterface(m_pIAccessor,IID_IRowset, ROWSET_INTERFACE,
|
|
(IUnknown **)&m_pIRowset)))
|
|
goto CLEANUP;
|
|
if(!(fSuccess &= VerifyInterface(m_pIAccessor,IID_IRowsetChange, ROWSET_INTERFACE,
|
|
(IUnknown **)&m_pIRowsetChange)))
|
|
goto CLEANUP;
|
|
|
|
do
|
|
{
|
|
// Get a row from the rowset
|
|
DBCOUNTITEM cRowsObtained=0;
|
|
HROW * prghRows=&rghRows[0];
|
|
hr = m_pIRowset->GetNextRows(NULL, 0, 1, &cRowsObtained, &prghRows);
|
|
if (S_OK == hr)
|
|
{
|
|
if (CHECK(hr = m_pIRowsetChange->DeleteRows(NULL, 1, rghRows, rgRowStatus), S_OK))
|
|
{
|
|
m_pTable->SubtractRow();
|
|
}
|
|
CHECK(hr = m_pIRowset->ReleaseRows(1, rghRows, NULL, NULL, NULL), S_OK);
|
|
rghRows[0] = DB_NULL_HROW;
|
|
}
|
|
} while (S_OK == hr);
|
|
|
|
fSuccess &= CHECK(hr, DB_S_ENDOFROWSET);
|
|
|
|
//Now add the single first row back in for the rest of the variations
|
|
if (!(fSuccess &= CHECK(m_pTable->Insert(g_uiRowNum),S_OK)))
|
|
odtLog << wszErrorInserting;
|
|
}
|
|
}
|
|
|
|
CLEANUP:
|
|
//Clean up
|
|
if (rghRows[0] != DB_NULL_HROW)
|
|
CHECK(m_pIRowset->ReleaseRows(1, rghRows, NULL, NULL, NULL), S_OK);
|
|
|
|
SAFE_RELEASE(m_pIRowsetChange);
|
|
//Release rowset so that for next variations we don't
|
|
//have an un updateable newly inserted hRow in the rowset
|
|
ReleaseRowsetObject();
|
|
SAFE_RELEASE(m_pIRowset);
|
|
|
|
//Create a new rowset for the next variations.
|
|
if (SettableProperty(DBPROP_IRowsetChange, DBPROPSET_ROWSET, (IUnknown *)m_pThisTestModule->m_pIUnknown, DATASOURCE_INTERFACE) &
|
|
SettableProperty(DBPROP_UPDATABILITY, DBPROPSET_ROWSET, (IUnknown *)m_pThisTestModule->m_pIUnknown, DATASOURCE_INTERFACE))
|
|
SetRowsetProperties(m_pDBPropSet, 1);
|
|
|
|
hr=CreateRowsetObject(SELECT_VALIDATIONORDER);
|
|
|
|
fSuccess &= CheckHr(hr);
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
//Try to get an IRowset interface
|
|
fSuccess &= COMPARE(VerifyInterface(m_pIAccessor,IID_IRowset, ROWSET_INTERFACE,
|
|
(IUnknown **)&m_pIRowset), TRUE);
|
|
}
|
|
}
|
|
|
|
if (fSuccess)
|
|
return TEST_PASS;
|
|
else
|
|
return TEST_FAIL;
|
|
|
|
}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(2)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc dwPart = DBPART_VALUE
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCCreateValidRowAccessors::Variation_2()
|
|
{
|
|
BOOL fSuccess = FALSE;
|
|
|
|
//Create Accessor with a binding using only DBCOLUMPART_VALUE
|
|
if (CHECK(GetAccessorAndBindings(m_pIAccessor, DBACCESSOR_ROWDATA,
|
|
&m_hAccessor, &m_rgBindings, &m_cBindings, &m_cbRowSize,
|
|
DBPART_VALUE | DBPART_LENGTH, ALL_COLS_BOUND,
|
|
FORWARD, NO_COLS_BY_REF, NULL, NULL,
|
|
NULL, DBTYPE_EMPTY, 0, NULL, NULL,
|
|
NO_COLS_OWNED_BY_PROV, DBPARAMIO_NOTPARAM,
|
|
m_fBindLongCols),S_OK))
|
|
|
|
// Now go through and remove the length binding for all but varnumeric bindings. Length
|
|
// is required for varnumeric bindings.
|
|
for (ULONG iBind = 0; iBind < m_cBindings; iBind++)
|
|
{
|
|
m_rgBindings[iBind].dwPart = DBPART_VALUE;
|
|
}
|
|
|
|
// Recreate the accessor since we've changed the bindings
|
|
TESTC_(m_pIAccessor->ReleaseAccessor(m_hAccessor, NULL), S_OK);
|
|
TESTC_(m_pIAccessor->CreateAccessor(DBACCESSOR_ROWDATA, m_cBindings, m_rgBindings, m_cbRowSize,
|
|
&m_hAccessor, NULL), S_OK);
|
|
|
|
//Verify the data is correctly brought back using the accessor
|
|
//(via either GetData or ReadData).
|
|
if (CHECK(UseRowAccessorAndVerify(m_hAccessor, m_cbRowSize, g_uiRowNum,
|
|
m_rgTableColOrds, m_cRowsetCols, m_rgBindings, m_cBindings),S_OK))
|
|
//GetBindings should return same values we've used to create the accessor
|
|
fSuccess = VerifyBindings(m_pIAccessor, m_rgBindings, m_cBindings, m_hAccessor, DBACCESSOR_ROWDATA);
|
|
|
|
CLEANUP:
|
|
|
|
//Clean up
|
|
if (m_hAccessor)
|
|
{
|
|
CHECK(m_pIAccessor->ReleaseAccessor(m_hAccessor, NULL), S_OK);
|
|
m_hAccessor = DB_NULL_HACCESSOR;
|
|
}
|
|
|
|
FREE_BINDINGS(&m_cBindings, &m_rgBindings);
|
|
return (fSuccess) ? TEST_PASS : TEST_FAIL;
|
|
}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(3)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc dwPart = DBPART_LENGTH
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCCreateValidRowAccessors::Variation_3()
|
|
{
|
|
BOOL fSuccess = TRUE;
|
|
|
|
|
|
//Create Accessor with a binding using only DBCOLUMPART_LENGTH
|
|
if (fSuccess &= CHECK(GetAccessorAndBindings(m_pIAccessor, DBACCESSOR_ROWDATA,
|
|
&m_hAccessor, &m_rgBindings, &m_cBindings, &m_cbRowSize,
|
|
DBPART_LENGTH, ALL_COLS_BOUND,
|
|
FORWARD, NO_COLS_BY_REF, NULL, NULL,
|
|
NULL, DBTYPE_EMPTY, 0, NULL, NULL,
|
|
NO_COLS_OWNED_BY_PROV, DBPARAMIO_NOTPARAM,
|
|
m_fBindLongCols),S_OK))
|
|
|
|
if (fSuccess &= CHECK(UseRowAccessorAndVerify(m_hAccessor, m_cbRowSize, g_uiRowNum,
|
|
m_rgTableColOrds, m_cRowsetCols, m_rgBindings, m_cBindings),S_OK))
|
|
//GetBindings should return same values we've used to create the accessor
|
|
fSuccess &= VerifyBindings(m_pIAccessor, m_rgBindings, m_cBindings, m_hAccessor, DBACCESSOR_ROWDATA);
|
|
|
|
//Clean up
|
|
if (m_hAccessor)
|
|
{
|
|
fSuccess &= CHECK(m_pIAccessor->ReleaseAccessor(m_hAccessor, NULL), S_OK);
|
|
m_hAccessor = DB_NULL_HACCESSOR;
|
|
}
|
|
|
|
FREE_BINDINGS(&m_cBindings, &m_rgBindings);
|
|
|
|
if (fSuccess)
|
|
return TEST_PASS;
|
|
else
|
|
return TEST_FAIL;
|
|
}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(4)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc dwPart = DBPART_STATUS
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCCreateValidRowAccessors::Variation_4()
|
|
{
|
|
BOOL fSuccess = FALSE;
|
|
|
|
|
|
//Create Accessor with a binding using only DBCOLUMPART_STATUS
|
|
if (CHECK(GetAccessorAndBindings(m_pIAccessor, DBACCESSOR_ROWDATA,
|
|
&m_hAccessor, &m_rgBindings, &m_cBindings, &m_cbRowSize,
|
|
DBPART_STATUS, ALL_COLS_BOUND,
|
|
FORWARD, NO_COLS_BY_REF, NULL, NULL,
|
|
NULL, DBTYPE_EMPTY, 0, NULL, NULL,
|
|
NO_COLS_OWNED_BY_PROV, DBPARAMIO_NOTPARAM,
|
|
m_fBindLongCols),S_OK))
|
|
|
|
//Verify the data is correctly brought back using the accessor
|
|
//(via either GetData or ReadData).
|
|
if (CHECK(UseRowAccessorAndVerify(m_hAccessor, m_cbRowSize, g_uiRowNum,
|
|
m_rgTableColOrds, m_cRowsetCols, m_rgBindings, m_cBindings),S_OK))
|
|
//GetBindings should return same values we've used to create the accessor
|
|
fSuccess = VerifyBindings(m_pIAccessor, m_rgBindings, m_cBindings, m_hAccessor, DBACCESSOR_ROWDATA);
|
|
|
|
//Clean up
|
|
if (m_hAccessor)
|
|
{
|
|
CHECK(m_pIAccessor->ReleaseAccessor(m_hAccessor, NULL), S_OK);
|
|
m_hAccessor = DB_NULL_HACCESSOR;
|
|
}
|
|
|
|
FREE_BINDINGS(&m_cBindings, &m_rgBindings);
|
|
|
|
if (fSuccess)
|
|
return TEST_PASS;
|
|
else
|
|
return TEST_FAIL;
|
|
}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(5)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc dwPart = DBCOLUMPART_LENGTH | DBCOLUMPART_STATUS
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCCreateValidRowAccessors::Variation_5()
|
|
{
|
|
BOOL fSuccess = FALSE;
|
|
|
|
|
|
//Create Accessor with a binding using only length and status
|
|
if (CHECK(GetAccessorAndBindings(m_pIAccessor, DBACCESSOR_ROWDATA,
|
|
&m_hAccessor, &m_rgBindings, &m_cBindings, &m_cbRowSize,
|
|
DBPART_LENGTH | DBPART_STATUS, ALL_COLS_BOUND,
|
|
FORWARD, NO_COLS_BY_REF, NULL, NULL,
|
|
NULL, DBTYPE_EMPTY, 0, NULL, NULL,
|
|
NO_COLS_OWNED_BY_PROV, DBPARAMIO_NOTPARAM,
|
|
m_fBindLongCols),S_OK))
|
|
|
|
//Verify the data is correctly brought back using the accessor
|
|
//(via either GetData or ReadData).
|
|
if (CHECK(UseRowAccessorAndVerify(m_hAccessor, m_cbRowSize, g_uiRowNum,
|
|
m_rgTableColOrds, m_cRowsetCols, m_rgBindings, m_cBindings),S_OK))
|
|
//GetBindings should return same values we've used to create the accessor
|
|
fSuccess = VerifyBindings(m_pIAccessor, m_rgBindings, m_cBindings, m_hAccessor, DBACCESSOR_ROWDATA);
|
|
|
|
//Clean up
|
|
if (m_hAccessor)
|
|
{
|
|
CHECK(m_pIAccessor->ReleaseAccessor(m_hAccessor, NULL), S_OK);
|
|
m_hAccessor = DB_NULL_HACCESSOR;
|
|
}
|
|
|
|
FREE_BINDINGS(&m_cBindings, &m_rgBindings);
|
|
|
|
if (fSuccess)
|
|
return TEST_PASS;
|
|
else
|
|
return TEST_FAIL;
|
|
}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(6)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc dwPart = DBCOLUMPART_LENGTH | DBCOLUMPART_STATUS | DBCOLUMPART_VALUE
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCCreateValidRowAccessors::Variation_6()
|
|
{
|
|
|
|
BOOL fSuccess = FALSE;
|
|
|
|
//Create Accessor with a binding using length, status and value
|
|
if (CHECK(GetAccessorAndBindings(m_pIAccessor,
|
|
DBACCESSOR_ROWDATA,
|
|
&m_hAccessor, &m_rgBindings, &m_cBindings, &m_cbRowSize,
|
|
DBPART_LENGTH | DBPART_STATUS | DBPART_VALUE,
|
|
ALL_COLS_BOUND, FORWARD, NO_COLS_BY_REF, NULL,
|
|
NULL, NULL, DBTYPE_EMPTY, 0, NULL, g_rgParamOrds,
|
|
NO_COLS_OWNED_BY_PROV, DBPARAMIO_INPUT, m_fBindLongCols),S_OK))
|
|
|
|
//Verify the data is correctly brought back using the accessor
|
|
//(via either GetData or ReadData).
|
|
if (CHECK(UseRowAccessorAndVerify(m_hAccessor, m_cbRowSize, g_uiRowNum,
|
|
m_rgTableColOrds, m_cRowsetCols, m_rgBindings, m_cBindings),S_OK))
|
|
//GetBindings should return same values we've used to create the accessor
|
|
fSuccess = VerifyBindings(m_pIAccessor, m_rgBindings, m_cBindings, m_hAccessor,
|
|
DBACCESSOR_ROWDATA);
|
|
|
|
//Clean up
|
|
if (m_hAccessor)
|
|
{
|
|
CHECK(m_pIAccessor->ReleaseAccessor(m_hAccessor, NULL), S_OK);
|
|
m_hAccessor = DB_NULL_HACCESSOR;
|
|
}
|
|
|
|
FREE_BINDINGS(&m_cBindings, &m_rgBindings);
|
|
|
|
if (fSuccess)
|
|
return TEST_PASS;
|
|
else
|
|
return TEST_FAIL;
|
|
}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(7)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc One optmized, one non optimized, using same fields
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCCreateValidRowAccessors::Variation_7()
|
|
{
|
|
BOOL fSuccess = FALSE;
|
|
HRESULT hr;
|
|
|
|
//Start with a clean rowset so optimized accessor creation is legal
|
|
ReleaseRowsetObject();
|
|
|
|
SAFE_RELEASE(m_pIRowset);
|
|
|
|
if (m_fBindLongCols == BLOB_LONG)
|
|
SetRowsetProperties(m_pDBPropSetLocate, 1);
|
|
|
|
hr=CreateRowsetObject(SELECT_VALIDATIONORDER);
|
|
|
|
if (!CheckHr(hr))
|
|
return TEST_FAIL;
|
|
|
|
if(!VerifyInterface(m_pIAccessor,IID_IRowset, ROWSET_INTERFACE,
|
|
(IUnknown **)&m_pIRowset))
|
|
return TEST_FAIL;
|
|
|
|
//Create an optmized accessor, using all the columns
|
|
if (CHECK(GetAccessorAndBindings(m_pIAccessor,
|
|
DBACCESSOR_ROWDATA | DBACCESSOR_OPTIMIZED,
|
|
&m_hAccessor, &m_rgBindings, &m_cBindings, &m_cbRowSize,
|
|
DBPART_LENGTH | DBPART_STATUS | DBPART_VALUE,
|
|
ALL_COLS_BOUND,
|
|
FORWARD, NO_COLS_BY_REF, NULL, NULL,
|
|
NULL, DBTYPE_EMPTY, 0, NULL, NULL,
|
|
NO_COLS_OWNED_BY_PROV, DBPARAMIO_NOTPARAM,
|
|
m_fBindLongCols),S_OK)
|
|
|
|
&&
|
|
|
|
//Create a non optimized accessor using the same columns
|
|
CHECK(GetAccessorAndBindings(m_pIAccessor, DBACCESSOR_ROWDATA,
|
|
&m_hAccessor2, &m_rgBindings2, &m_cBindings2, &m_cbRowSize2,
|
|
DBPART_LENGTH | DBPART_STATUS | DBPART_VALUE,
|
|
ALL_COLS_BOUND,
|
|
FORWARD, NO_COLS_BY_REF, NULL, NULL,
|
|
NULL, DBTYPE_EMPTY, 0, NULL, NULL,
|
|
NO_COLS_OWNED_BY_PROV, DBPARAMIO_NOTPARAM,
|
|
m_fBindLongCols),S_OK))
|
|
|
|
|
|
//Verify the data is correctly brought back using both accessors
|
|
//(via either GetData or ReadData).
|
|
if(g_fCmdSupported)
|
|
{
|
|
if (CHECK(UseRowAccessorAndVerify(m_hAccessor, m_cbRowSize, g_uiRowNum,
|
|
m_rgTableColOrds, m_cRowsetCols, m_rgBindings, m_cBindings,
|
|
FALSE, TRUE),S_OK)) //Keep same rows to be gotten by next call
|
|
{
|
|
if (CHECK(UseRowAccessorAndVerify(m_hAccessor2, m_cbRowSize2, g_uiRowNum,
|
|
m_rgTableColOrds, m_cRowsetCols, m_rgBindings2, m_cBindings2),S_OK))
|
|
|
|
//Check first accessor with GetBindings
|
|
fSuccess = VerifyBindings(m_pIAccessor, m_rgBindings, m_cBindings, m_hAccessor,
|
|
DBACCESSOR_ROWDATA | DBACCESSOR_OPTIMIZED);
|
|
|
|
//Check second accessor with GetBindings
|
|
fSuccess &= VerifyBindings(m_pIAccessor, m_rgBindings2, m_cBindings2, m_hAccessor2, DBACCESSOR_ROWDATA);
|
|
}
|
|
else
|
|
fSuccess = TRUE;
|
|
//We have to clean up since we kept the row in UseRowAccessorAndVerify
|
|
if(m_hRow && m_fIRowset)
|
|
{
|
|
m_pIRowset->ReleaseRows(m_cRowsObtained,&m_hRow, NULL, NULL,NULL);
|
|
m_hRow = DB_NULL_HROW;
|
|
}
|
|
}
|
|
|
|
else
|
|
fSuccess = TRUE;
|
|
|
|
//Clean Up
|
|
if (m_hAccessor)
|
|
{
|
|
CHECK(m_pIAccessor->ReleaseAccessor(m_hAccessor, NULL), S_OK);
|
|
m_hAccessor = DB_NULL_HACCESSOR;
|
|
}
|
|
if (m_hAccessor2)
|
|
{
|
|
CHECK(m_pIAccessor->ReleaseAccessor(m_hAccessor2, NULL), S_OK);
|
|
m_hAccessor2 = DB_NULL_HACCESSOR;
|
|
}
|
|
|
|
FREE_BINDINGS(&m_cBindings, &m_rgBindings);
|
|
FREE_BINDINGS(&m_cBindings2, &m_rgBindings2);
|
|
|
|
//Make it clear to other variations that hRow is invalid
|
|
m_hRow = DB_NULL_HROW;
|
|
|
|
if (fSuccess)
|
|
return TEST_PASS;
|
|
else
|
|
return TEST_FAIL;
|
|
}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(8)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc One non-optimized, one optimized, using same fields - different creation sequence
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCCreateValidRowAccessors::Variation_8()
|
|
{
|
|
BOOL fSuccess = FALSE;
|
|
HRESULT hr;
|
|
|
|
//Start with a clean rowset so optimized accessor creation is legal
|
|
ReleaseRowsetObject();
|
|
|
|
SAFE_RELEASE(m_pIRowset);
|
|
|
|
hr=CreateRowsetObject(SELECT_VALIDATIONORDER);
|
|
|
|
if (!CheckHr(hr))
|
|
return TEST_FAIL;
|
|
|
|
if(!VerifyInterface(m_pIAccessor,IID_IRowset, ROWSET_INTERFACE,
|
|
(IUnknown **)&m_pIRowset))
|
|
return TEST_FAIL;
|
|
|
|
//Create a non optmized accessor, using all the columns
|
|
if (CHECK(GetAccessorAndBindings(m_pIAccessor, DBACCESSOR_ROWDATA,
|
|
&m_hAccessor, &m_rgBindings, &m_cBindings, &m_cbRowSize,
|
|
DBPART_LENGTH | DBPART_STATUS | DBPART_VALUE,
|
|
ALL_COLS_BOUND,
|
|
FORWARD, NO_COLS_BY_REF, NULL, NULL,
|
|
NULL, DBTYPE_EMPTY, 0, NULL, NULL,
|
|
NO_COLS_OWNED_BY_PROV, DBPARAMIO_NOTPARAM,
|
|
m_fBindLongCols),S_OK)
|
|
|
|
&&
|
|
|
|
//Create an optimized accessor using the same columns
|
|
CHECK(GetAccessorAndBindings(m_pIAccessor,
|
|
DBACCESSOR_ROWDATA | DBACCESSOR_OPTIMIZED,
|
|
&m_hAccessor2, &m_rgBindings2, &m_cBindings2, &m_cbRowSize2,
|
|
DBPART_LENGTH | DBPART_STATUS | DBPART_VALUE,
|
|
ALL_COLS_BOUND,
|
|
FORWARD, NO_COLS_BY_REF, NULL, NULL,
|
|
NULL, DBTYPE_EMPTY, 0, NULL, NULL,
|
|
NO_COLS_OWNED_BY_PROV, DBPARAMIO_NOTPARAM,
|
|
m_fBindLongCols),S_OK))
|
|
|
|
|
|
//Verify the data is correctly brought back using both accessors
|
|
//(via either GetData or ReadData). NOTE: we use cBindings for
|
|
//number of columns in rowset, since these are the same value here
|
|
if(g_fCmdSupported)
|
|
{
|
|
if (CHECK(UseRowAccessorAndVerify(m_hAccessor, m_cbRowSize, g_uiRowNum,
|
|
m_rgTableColOrds, m_cRowsetCols, m_rgBindings, m_cBindings,
|
|
FALSE, TRUE),S_OK)) //Keep same rows to be gotten by next call
|
|
{
|
|
if (CHECK(UseRowAccessorAndVerify(m_hAccessor2, m_cbRowSize2, g_uiRowNum,
|
|
m_rgTableColOrds, m_cRowsetCols, m_rgBindings2, m_cBindings2),S_OK))
|
|
//Check first accessor with GetBindings
|
|
fSuccess = VerifyBindings(m_pIAccessor, m_rgBindings, m_cBindings, m_hAccessor, DBACCESSOR_ROWDATA) &&
|
|
//Check second accessor with GetBindings
|
|
VerifyBindings(m_pIAccessor, m_rgBindings2, m_cBindings2, m_hAccessor2,
|
|
DBACCESSOR_ROWDATA | DBACCESSOR_OPTIMIZED);
|
|
}
|
|
//We have to clean up since we kept the row in UseRowAccessorAndVerify
|
|
if(m_hRow && m_fIRowset)
|
|
{
|
|
m_pIRowset->ReleaseRows(m_cRowsObtained,&m_hRow, NULL, NULL,NULL);
|
|
m_hRow = DB_NULL_HROW;
|
|
}
|
|
}
|
|
else
|
|
fSuccess = TRUE;
|
|
|
|
//Clean Up
|
|
if (m_hAccessor)
|
|
{
|
|
CHECK(m_pIAccessor->ReleaseAccessor(m_hAccessor, NULL), S_OK);
|
|
m_hAccessor = DB_NULL_HACCESSOR;
|
|
}
|
|
if (m_hAccessor2)
|
|
{
|
|
CHECK(m_pIAccessor->ReleaseAccessor(m_hAccessor2, NULL), S_OK);
|
|
m_hAccessor2 = DB_NULL_HACCESSOR;
|
|
}
|
|
|
|
FREE_BINDINGS(&m_cBindings, &m_rgBindings);
|
|
FREE_BINDINGS(&m_cBindings2, &m_rgBindings2);
|
|
|
|
//Make it clear to other variations that hRow is invalid
|
|
m_hRow = DB_NULL_HROW;
|
|
|
|
if (fSuccess)
|
|
return TEST_PASS;
|
|
else
|
|
return TEST_FAIL;
|
|
}
|
|
|
|
// }}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(9)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc One optimized, one non-optimized, using different fields
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCCreateValidRowAccessors::Variation_9()
|
|
{
|
|
BOOL fSuccess = FALSE;
|
|
DBORDINAL cCols;
|
|
DBORDINAL cCols2;
|
|
HRESULT hr;
|
|
|
|
//Start with a clean rowset so optimized accessor creation is legal
|
|
ReleaseRowsetObject();
|
|
SAFE_RELEASE(m_pIRowset);
|
|
|
|
hr=CreateRowsetObject(SELECT_VALIDATIONORDER);
|
|
|
|
if (!CheckHr(hr))
|
|
return TEST_FAIL;
|
|
|
|
if(!VerifyInterface(m_pIAccessor,IID_IRowset, ROWSET_INTERFACE,
|
|
(IUnknown **)&m_pIRowset))
|
|
return TEST_FAIL;
|
|
|
|
|
|
//Create an optmized accessor, using odd columns
|
|
if (CHECK(GetAccessorAndBindings(m_pIAccessor,
|
|
DBACCESSOR_ROWDATA | DBACCESSOR_OPTIMIZED,
|
|
&m_hAccessor, &m_rgBindings, &m_cBindings, &m_cbRowSize,
|
|
DBPART_LENGTH | DBPART_STATUS | DBPART_VALUE,
|
|
ODD_COLS_BOUND, FORWARD, NO_COLS_BY_REF, NULL, &cCols,
|
|
NULL, DBTYPE_EMPTY, 0, NULL, NULL,
|
|
NO_COLS_OWNED_BY_PROV, DBPARAMIO_NOTPARAM,
|
|
m_fBindLongCols),S_OK)
|
|
|
|
&&
|
|
|
|
//Create a non optimized accessor using different columns (even ones)
|
|
CHECK(GetAccessorAndBindings(m_pIAccessor, DBACCESSOR_ROWDATA,
|
|
&m_hAccessor2, &m_rgBindings2, &m_cBindings2, &m_cbRowSize2,
|
|
DBPART_LENGTH | DBPART_STATUS | DBPART_VALUE,
|
|
EVEN_COLS_BOUND, FORWARD, NO_COLS_BY_REF, NULL, &cCols2,
|
|
NULL, DBTYPE_EMPTY, 0, NULL, NULL,
|
|
NO_COLS_OWNED_BY_PROV, DBPARAMIO_NOTPARAM,
|
|
m_fBindLongCols),S_OK))
|
|
{
|
|
//This should be the same number since its the same rowset
|
|
COMPARE(cCols,cCols2);
|
|
|
|
//Verify the data is correctly brought back using both accessors
|
|
//(via either GetData or ReadData).
|
|
if(g_fCmdSupported)
|
|
{
|
|
if (CHECK(UseRowAccessorAndVerify(m_hAccessor, m_cbRowSize, g_uiRowNum,
|
|
m_rgTableColOrds, cCols, m_rgBindings, m_cBindings,
|
|
FALSE, TRUE),S_OK)) //Keep same rows to be gotten by next call
|
|
{
|
|
if (CHECK(UseRowAccessorAndVerify(m_hAccessor2, m_cbRowSize2, g_uiRowNum,
|
|
m_rgTableColOrds, cCols2, m_rgBindings2, m_cBindings2),S_OK))
|
|
//Check first accessor with GetBindings
|
|
fSuccess = VerifyBindings(m_pIAccessor, m_rgBindings, m_cBindings, m_hAccessor,
|
|
DBACCESSOR_ROWDATA | DBACCESSOR_OPTIMIZED) &&
|
|
//Check second accessor with GetBindings
|
|
VerifyBindings(m_pIAccessor, m_rgBindings2, m_cBindings2, m_hAccessor2, DBACCESSOR_ROWDATA);
|
|
}
|
|
//We have to clean up since we kept the row in UseRowAccessorAndVerify
|
|
if(m_hRow && m_fIRowset)
|
|
{
|
|
m_pIRowset->ReleaseRows(m_cRowsObtained,&m_hRow,NULL, NULL,NULL);
|
|
m_hRow = DB_NULL_HROW;
|
|
}
|
|
}
|
|
else
|
|
fSuccess = TRUE;
|
|
|
|
}
|
|
|
|
//Clean Up
|
|
if (m_hAccessor)
|
|
{
|
|
CHECK(m_pIAccessor->ReleaseAccessor(m_hAccessor, NULL), S_OK);
|
|
m_hAccessor = DB_NULL_HACCESSOR;
|
|
}
|
|
if (m_hAccessor2)
|
|
{
|
|
CHECK(m_pIAccessor->ReleaseAccessor(m_hAccessor2, NULL), S_OK);
|
|
m_hAccessor2 = DB_NULL_HACCESSOR;
|
|
}
|
|
|
|
FREE_BINDINGS(&m_cBindings, &m_rgBindings);
|
|
FREE_BINDINGS(&m_cBindings2, &m_rgBindings2);
|
|
|
|
//Make it clear to other variations that hRow is invalid
|
|
m_hRow = DB_NULL_HROW;
|
|
|
|
if (fSuccess)
|
|
return TEST_PASS;
|
|
else
|
|
return TEST_FAIL;
|
|
}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(10)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc Two optimized, using different fields
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCCreateValidRowAccessors::Variation_10()
|
|
{
|
|
BOOL fSuccess = FALSE;
|
|
DBORDINAL cCols;
|
|
DBORDINAL cCols2;
|
|
HRESULT hr;
|
|
|
|
//Start with a clean rowset so optimized accessor creation is legal
|
|
ReleaseRowsetObject();
|
|
SAFE_RELEASE(m_pIRowset);
|
|
|
|
hr=CreateRowsetObject(SELECT_VALIDATIONORDER);
|
|
|
|
if (!CheckHr(hr))
|
|
return TEST_FAIL;
|
|
|
|
if(!VerifyInterface(m_pIAccessor,IID_IRowset, ROWSET_INTERFACE,
|
|
(IUnknown **)&m_pIRowset))
|
|
return TEST_FAIL;
|
|
|
|
//Create an optmized accessor, using odd columns
|
|
if (CHECK(GetAccessorAndBindings(m_pIAccessor,
|
|
DBACCESSOR_ROWDATA | DBACCESSOR_OPTIMIZED,
|
|
&m_hAccessor, &m_rgBindings, &m_cBindings, &m_cbRowSize,
|
|
DBPART_LENGTH | DBPART_STATUS | DBPART_VALUE,
|
|
ODD_COLS_BOUND, FORWARD, NO_COLS_BY_REF, NULL, &cCols,
|
|
NULL, DBTYPE_EMPTY, 0, NULL, NULL,
|
|
NO_COLS_OWNED_BY_PROV, DBPARAMIO_NOTPARAM,
|
|
m_fBindLongCols),S_OK)
|
|
|
|
&&
|
|
|
|
//Create another optimized accessor using different columns (even ones)
|
|
CHECK(GetAccessorAndBindings(m_pIAccessor,
|
|
DBACCESSOR_ROWDATA | DBACCESSOR_OPTIMIZED,
|
|
&m_hAccessor2, &m_rgBindings2, &m_cBindings2, &m_cbRowSize2,
|
|
DBPART_LENGTH | DBPART_STATUS | DBPART_VALUE,
|
|
EVEN_COLS_BOUND, FORWARD, NO_COLS_BY_REF, NULL, &cCols2,
|
|
NULL, DBTYPE_EMPTY, 0, NULL, NULL,
|
|
NO_COLS_OWNED_BY_PROV, DBPARAMIO_NOTPARAM,
|
|
m_fBindLongCols),S_OK))
|
|
{
|
|
//This should be the same number since its the same rowset
|
|
COMPARE(cCols,cCols2);
|
|
|
|
//Verify the data is correctly brought back using both accessors
|
|
//(via either GetData or ReadData).
|
|
if(g_fCmdSupported)
|
|
{
|
|
if (CHECK(UseRowAccessorAndVerify(m_hAccessor, m_cbRowSize, g_uiRowNum,
|
|
m_rgTableColOrds, cCols, m_rgBindings, m_cBindings,
|
|
FALSE, TRUE),S_OK)) //Keep same rows to be gotten by next call
|
|
{
|
|
if (CHECK(UseRowAccessorAndVerify(m_hAccessor2, m_cbRowSize2, g_uiRowNum,
|
|
m_rgTableColOrds, cCols2, m_rgBindings2, m_cBindings2),S_OK))
|
|
//Check first accessor with GetBindings
|
|
fSuccess = VerifyBindings(m_pIAccessor, m_rgBindings, m_cBindings, m_hAccessor,
|
|
DBACCESSOR_ROWDATA | DBACCESSOR_OPTIMIZED) &&
|
|
//Check second accessor with GetBindings
|
|
VerifyBindings(m_pIAccessor, m_rgBindings2, m_cBindings2, m_hAccessor2,
|
|
DBACCESSOR_ROWDATA | DBACCESSOR_OPTIMIZED);
|
|
}
|
|
//We have to clean up since we kept the row in UseRowAccessorAndVerify
|
|
if(m_hRow && m_fIRowset)
|
|
{
|
|
m_pIRowset->ReleaseRows(m_cRowsObtained,&m_hRow, NULL, NULL,NULL);
|
|
m_hRow = DB_NULL_HROW;
|
|
}
|
|
}
|
|
else
|
|
fSuccess = TRUE;
|
|
|
|
}
|
|
|
|
|
|
//Clean Up
|
|
if (m_hAccessor)
|
|
{
|
|
CHECK(m_pIAccessor->ReleaseAccessor(m_hAccessor, NULL), S_OK);
|
|
m_hAccessor = DB_NULL_HACCESSOR;
|
|
}
|
|
if (m_hAccessor2)
|
|
{
|
|
CHECK(m_pIAccessor->ReleaseAccessor(m_hAccessor2, NULL), S_OK);
|
|
m_hAccessor2 = DB_NULL_HACCESSOR;
|
|
}
|
|
|
|
FREE_BINDINGS(&m_cBindings, &m_rgBindings);
|
|
FREE_BINDINGS(&m_cBindings2, &m_rgBindings2);
|
|
|
|
//Make it clear to other variations that hRow is invalid
|
|
m_hRow = DB_NULL_HROW;
|
|
|
|
if (fSuccess)
|
|
return TEST_PASS;
|
|
else
|
|
return TEST_FAIL;
|
|
|
|
}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(11)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc Two non-optimized, using same fields
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCCreateValidRowAccessors::Variation_11()
|
|
{
|
|
BOOL fSuccess = FALSE;
|
|
HRESULT hr;
|
|
|
|
//Start with a clean rowset so optimized accessor creation is legal
|
|
ReleaseRowsetObject();
|
|
SAFE_RELEASE(m_pIRowset);
|
|
|
|
//Create a new rowset for the next variations.
|
|
// We have to reset any properties we wanted on the rowset for IOpenRowset.
|
|
if (SettableProperty(DBPROP_IRowsetChange, DBPROPSET_ROWSET, (IUnknown *)m_pThisTestModule->m_pIUnknown, DATASOURCE_INTERFACE) &
|
|
SettableProperty(DBPROP_UPDATABILITY, DBPROPSET_ROWSET, (IUnknown *)m_pThisTestModule->m_pIUnknown, DATASOURCE_INTERFACE))
|
|
SetRowsetProperties(m_pDBPropSet, 1);
|
|
|
|
hr=CreateRowsetObject(SELECT_VALIDATIONORDER);
|
|
|
|
if (!CheckHr(hr))
|
|
return TEST_FAIL;
|
|
|
|
if(!VerifyInterface(m_pIAccessor,IID_IRowset, ROWSET_INTERFACE,
|
|
(IUnknown **)&m_pIRowset))
|
|
return TEST_FAIL;
|
|
|
|
|
|
//Create an optmized accessor, using all columns
|
|
if (CHECK(GetAccessorAndBindings(m_pIAccessor,
|
|
DBACCESSOR_ROWDATA,
|
|
&m_hAccessor, &m_rgBindings, &m_cBindings, &m_cbRowSize,
|
|
DBPART_LENGTH | DBPART_STATUS | DBPART_VALUE,
|
|
ALL_COLS_BOUND,
|
|
FORWARD, NO_COLS_BY_REF, NULL, NULL,
|
|
NULL, DBTYPE_EMPTY, 0, NULL, NULL,
|
|
NO_COLS_OWNED_BY_PROV, DBPARAMIO_NOTPARAM,
|
|
m_fBindLongCols),S_OK)
|
|
|
|
&&
|
|
|
|
//Create another optimized accessor with same columns
|
|
CHECK(GetAccessorAndBindings(m_pIAccessor,
|
|
DBACCESSOR_ROWDATA,
|
|
&m_hAccessor2, &m_rgBindings2, &m_cBindings2, &m_cbRowSize2,
|
|
DBPART_LENGTH | DBPART_STATUS | DBPART_VALUE,
|
|
ALL_COLS_BOUND,
|
|
FORWARD, NO_COLS_BY_REF, NULL, NULL,
|
|
NULL, DBTYPE_EMPTY, 0, NULL, NULL,
|
|
NO_COLS_OWNED_BY_PROV, DBPARAMIO_NOTPARAM,
|
|
m_fBindLongCols),S_OK))
|
|
|
|
//Check that GetBindings works here
|
|
VerifyBindings(m_pIAccessor, m_rgBindings2, m_cBindings2, m_hAccessor2,
|
|
DBACCESSOR_ROWDATA);
|
|
|
|
//Verify the data is correctly brought back using both accessors
|
|
//(via either GetData or ReadData). NOTE: we use cBindings for
|
|
//number of columns in rowset, since these are the same value here
|
|
if(g_fCmdSupported)
|
|
{
|
|
if (CHECK(UseRowAccessorAndVerify(m_hAccessor, m_cbRowSize, g_uiRowNum,
|
|
m_rgTableColOrds, m_cRowsetCols, m_rgBindings, m_cBindings,
|
|
FALSE, TRUE),S_OK)) //Keep same rows to be gotten by next call
|
|
{
|
|
//Specify that we don't want to GetNextRows again, so
|
|
//we can read the first row a second time, hence true
|
|
//as the last param
|
|
if (CHECK(UseRowAccessorAndVerify(m_hAccessor2, m_cbRowSize2, g_uiRowNum,
|
|
m_rgTableColOrds, m_cRowsetCols, m_rgBindings2, m_cBindings2),S_OK))
|
|
|
|
//Check first accessor with GetBindings
|
|
fSuccess = VerifyBindings(m_pIAccessor, m_rgBindings, m_cBindings, m_hAccessor,
|
|
DBACCESSOR_ROWDATA);
|
|
}
|
|
//We have to clean up since we kept the row in UseRowAccessorAndVerify
|
|
if(m_hRow && m_fIRowset)
|
|
{
|
|
m_pIRowset->ReleaseRows(m_cRowsObtained,&m_hRow,NULL, NULL,NULL);
|
|
m_hRow = DB_NULL_HROW;
|
|
}
|
|
}
|
|
|
|
else
|
|
fSuccess = TRUE;
|
|
|
|
//Clean Up
|
|
if (m_hAccessor)
|
|
{
|
|
CHECK(m_pIAccessor->ReleaseAccessor(m_hAccessor, NULL), S_OK);
|
|
m_hAccessor = DB_NULL_HACCESSOR;
|
|
}
|
|
if (m_hAccessor2)
|
|
{
|
|
CHECK(m_pIAccessor->ReleaseAccessor(m_hAccessor2, NULL), S_OK);
|
|
m_hAccessor2 = DB_NULL_HACCESSOR;
|
|
}
|
|
|
|
FREE_BINDINGS(&m_cBindings, &m_rgBindings);
|
|
FREE_BINDINGS(&m_cBindings2, &m_rgBindings2);
|
|
|
|
//Make it clear to other variations that hRow is invalid
|
|
m_hRow = DB_NULL_HROW;
|
|
|
|
if (fSuccess)
|
|
return TEST_PASS;
|
|
else
|
|
return TEST_FAIL;
|
|
|
|
}
|
|
// }}
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(12)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc Multiple bindings for same column in one accessor
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCCreateValidRowAccessors::Variation_12()
|
|
{
|
|
BOOL fSuccess = FALSE;
|
|
DBBINDING rgMultiBind[2];
|
|
DBBINDSTATUS * rgStatus = NULL;
|
|
IConvertType * pIConvertType = NULL;
|
|
IColumnsInfo * pIColumnsInfo = NULL;
|
|
HRESULT hrExp = NOERROR;
|
|
HRESULT hr = NOERROR;
|
|
DBORDINAL cColumns;
|
|
DBCOLUMNINFO * pColInfo=NULL;
|
|
WCHAR * pStringsBuffer=NULL;
|
|
|
|
ULONG ulBindIdx=0;
|
|
DBLENGTH ulOffset=0;
|
|
DBLENGTH cbRowSize=0;
|
|
DBORDINAL iColIdx=0;
|
|
|
|
//Use this routine to build bindings
|
|
if (!CHECK(GetAccessorAndBindings(m_pIAccessor,
|
|
DBACCESSOR_ROWDATA,
|
|
&m_hAccessor, &m_rgBindings, &m_cBindings, &m_cbRowSize,
|
|
DBPART_LENGTH | DBPART_STATUS | DBPART_VALUE,
|
|
ALL_COLS_BOUND,
|
|
FORWARD, NO_COLS_BY_REF, NULL, NULL,
|
|
NULL, DBTYPE_EMPTY, 0, NULL, NULL,
|
|
NO_COLS_OWNED_BY_PROV, DBPARAMIO_NOTPARAM,
|
|
m_fBindLongCols),S_OK))
|
|
goto CLEANUP;
|
|
|
|
//Now release accessor since we'll make a different one
|
|
CHECK(m_pIAccessor->ReleaseAccessor(m_hAccessor, NULL),S_OK);
|
|
m_hAccessor = DB_NULL_HACCESSOR;
|
|
|
|
if (!VerifyInterface(m_pIRowset, IID_IConvertType, ROWSET_INTERFACE,(IUnknown **) &pIConvertType))
|
|
goto CLEANUP;
|
|
|
|
if (!VerifyInterface(m_pIRowset, IID_IColumnsInfo, ROWSET_INTERFACE,(IUnknown **) &pIColumnsInfo))
|
|
goto CLEANUP;
|
|
|
|
// Get column information
|
|
if (!CHECK(pIColumnsInfo->GetColumnInfo(&cColumns, &pColInfo, &pStringsBuffer), S_OK))
|
|
goto CLEANUP;
|
|
|
|
//Any failure from here on will set this to false,
|
|
fSuccess = TRUE;
|
|
|
|
//For each column, create an accessor with two bindings for same col
|
|
//and make sure we can GetData back correctly using it.
|
|
//NOTE: This assumes that DBTYPE_WSTR will be a mandatory coersion.
|
|
for (ulBindIdx=0; ulBindIdx<m_cBindings; ulBindIdx++)
|
|
{
|
|
//Use the default binding type for one binding
|
|
CopyBindings(&rgMultiBind[0], &m_rgBindings[ulBindIdx]);
|
|
//Adjust offsets to use beginning of data buffer
|
|
rgMultiBind[0].obStatus = offsetof(DATA, sStatus);
|
|
rgMultiBind[0].obLength = offsetof(DATA, ulLength);
|
|
rgMultiBind[0].obValue = offsetof(DATA, bValue);
|
|
|
|
//Find start of next binding in buffer
|
|
ulOffset = offsetof(DATA, bValue) + rgMultiBind[0].cbMaxLen;
|
|
ulOffset = ROUND_UP(ulOffset, ROUND_UP_AMOUNT);
|
|
|
|
//Bind same column, except make bind type wchar
|
|
CopyBindings(&rgMultiBind[1], &m_rgBindings[ulBindIdx]);
|
|
rgMultiBind[1].wType = DBTYPE_WSTR;
|
|
|
|
//Move offsets for second binding to after first binding
|
|
rgMultiBind[1].obStatus = ulOffset + offsetof(DATA, sStatus);
|
|
rgMultiBind[1].obLength = ulOffset + offsetof(DATA, ulLength);
|
|
rgMultiBind[1].obValue = ulOffset + offsetof(DATA, bValue);
|
|
|
|
ulOffset = ulOffset + offsetof(DATA,bValue) + rgMultiBind[1].cbMaxLen;
|
|
ulOffset = ROUND_UP(ulOffset, ROUND_UP_AMOUNT);
|
|
|
|
rgStatus = (DBBINDSTATUS *)m_pIMalloc->Alloc(2 * sizeof(DBBINDSTATUS));
|
|
if (!rgStatus)
|
|
goto CLEANUP;
|
|
|
|
// Adjust cbMaxLen and cbRowSize. In general given a DBTYPE we don't know how much
|
|
// space is needed for the WSTR representation.
|
|
switch(rgMultiBind[0].wType)
|
|
{
|
|
case DBTYPE_WSTR:
|
|
// The binding is already the right size, do nothing
|
|
break;
|
|
case DBTYPE_STR:
|
|
// The binding is half that needed
|
|
rgMultiBind[1].cbMaxLen = rgMultiBind[0].cbMaxLen * 2 + sizeof(WCHAR);
|
|
break;
|
|
case DBTYPE_BYTES:
|
|
// The binding is one fourth that needed
|
|
// One binary digit becomes two wchars, each wchar is two bytes
|
|
rgMultiBind[1].cbMaxLen = rgMultiBind[0].cbMaxLen * 4 + sizeof(WCHAR);
|
|
break;
|
|
default:
|
|
// We'll set it to a minimum of MAX_BIND_LIMIT
|
|
rgMultiBind[1].cbMaxLen = MAX_BIND_LIMIT;
|
|
}
|
|
|
|
// Now adjust cbRowSize
|
|
cbRowSize = rgMultiBind[1].obValue - rgMultiBind[0].obStatus + rgMultiBind[1].cbMaxLen;
|
|
|
|
// Find the index into the columnsinfo for this column
|
|
iColIdx = rgMultiBind[1].iOrdinal;
|
|
if (pColInfo[0].iOrdinal)
|
|
iColIdx--; // If we don't have the bookmark column our index is one less
|
|
|
|
//Check whether provider supports the coersion
|
|
if(FAILED(hr = pIConvertType->CanConvert(pColInfo[iColIdx].wType, rgMultiBind[1].wType, DBCONVERTFLAGS_COLUMN)))
|
|
goto CLEANUP;
|
|
|
|
// Conversion to WSTR is mandatory for all providers
|
|
CHECK(hr, S_OK);
|
|
|
|
//Now create accessor with these two bindings
|
|
CHECK(hr = m_pIAccessor->CreateAccessor(DBACCESSOR_ROWDATA,
|
|
2, rgMultiBind, cbRowSize, &m_hAccessor, rgStatus),hrExp);
|
|
|
|
if(hr == DB_E_ERRORSOCCURRED)
|
|
{
|
|
CHECK(rgStatus[0],DBBINDSTATUS_OK);
|
|
CHECK(rgStatus[1],DBBINDSTATUS_UNSUPPORTEDCONVERSION);
|
|
COMPARE(m_hAccessor, 0);
|
|
}
|
|
else
|
|
{
|
|
//Try to use the accessor
|
|
if (!CHECK(UseRowAccessorAndVerify(m_hAccessor, cbRowSize, g_uiRowNum,
|
|
m_rgTableColOrds, m_cRowsetCols, rgMultiBind, 2),S_OK))
|
|
{
|
|
fSuccess = FALSE;
|
|
goto CLEANUP;
|
|
}
|
|
|
|
//If either of these fail, increment the error count,
|
|
//but don't exit variation, since this isn't what
|
|
//we're really testing here
|
|
COMPARE(VerifyBindings(m_pIAccessor, rgMultiBind, 2, m_hAccessor,
|
|
DBACCESSOR_ROWDATA), TRUE);
|
|
|
|
CHECK(m_pIAccessor->ReleaseAccessor(m_hAccessor, NULL),S_OK);
|
|
m_hAccessor = DB_NULL_HACCESSOR;
|
|
}
|
|
PROVIDER_FREE(rgStatus);
|
|
}
|
|
|
|
CLEANUP:
|
|
|
|
if (m_hAccessor)
|
|
{
|
|
m_pIAccessor->ReleaseAccessor(m_hAccessor, NULL);
|
|
m_hAccessor = DB_NULL_HACCESSOR;
|
|
}
|
|
|
|
FREE_BINDINGS(&m_cBindings, &m_rgBindings);
|
|
SAFE_RELEASE(pIConvertType);
|
|
SAFE_RELEASE(pIColumnsInfo);
|
|
PROVIDER_FREE(pColInfo);
|
|
PROVIDER_FREE(pStringsBuffer);
|
|
PROVIDER_FREE(rgStatus);
|
|
|
|
if (fSuccess)
|
|
return TEST_PASS;
|
|
else
|
|
return TEST_FAIL;
|
|
|
|
}
|
|
// }}
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(13)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc All types bound BY_REF, without DBMEMOWNER_PROVIDEROWNED
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCCreateValidRowAccessors::Variation_13()
|
|
{
|
|
BOOL fSuccess = FALSE;
|
|
|
|
//Get accessor with all cols BY_REF
|
|
TESTC_(GetAccessorAndBindings(m_pIAccessor,
|
|
DBACCESSOR_ROWDATA,
|
|
&m_hAccessor, &m_rgBindings, &m_cBindings, &m_cbRowSize,
|
|
DBPART_LENGTH | DBPART_STATUS | DBPART_VALUE,
|
|
ALL_COLS_BOUND, FORWARD, SUPPORTED_COLS_BY_REF,
|
|
NULL, NULL,
|
|
NULL, DBTYPE_EMPTY, 0, NULL, NULL,
|
|
NO_COLS_OWNED_BY_PROV, DBPARAMIO_NOTPARAM,
|
|
m_fBindLongCols),S_OK);
|
|
|
|
//Verify the data is correctly brought back using accessors
|
|
TESTC_(UseRowAccessorAndVerify(m_hAccessor, m_cbRowSize, g_uiRowNum,
|
|
m_rgTableColOrds, m_cBindings, m_rgBindings, m_cBindings),S_OK);
|
|
|
|
//Check first accessor with GetBindings
|
|
TESTC(VerifyBindings(m_pIAccessor, m_rgBindings, m_cBindings, m_hAccessor,
|
|
DBACCESSOR_ROWDATA));
|
|
|
|
fSuccess = TRUE;
|
|
|
|
CLEANUP:
|
|
|
|
if (m_hAccessor)
|
|
{
|
|
m_pIAccessor->ReleaseAccessor(m_hAccessor, NULL);
|
|
m_hAccessor = DB_NULL_HACCESSOR;
|
|
}
|
|
|
|
FREE_BINDINGS(&m_cBindings, &m_rgBindings);
|
|
|
|
if (fSuccess)
|
|
return TEST_PASS;
|
|
else
|
|
return TEST_FAIL;
|
|
|
|
}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(14)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc Fixed types bound BY_REF, without DBMEMOWNER_PROVIDEROWNED
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCCreateValidRowAccessors::Variation_14()
|
|
{
|
|
BOOL fSuccess = FALSE;
|
|
DBORDINAL cCols;
|
|
|
|
//Get accessor with fixed data type cols bound BY_REF
|
|
TESTC_(GetAccessorAndBindings(m_pIAccessor,
|
|
DBACCESSOR_ROWDATA,
|
|
&m_hAccessor, &m_rgBindings, &m_cBindings, &m_cbRowSize,
|
|
DBPART_LENGTH | DBPART_STATUS | DBPART_VALUE,
|
|
ALL_COLS_BOUND, FORWARD, SUPPORTED_FIXED_LEN_COLS_BY_REF, NULL, &cCols,
|
|
NULL, DBTYPE_EMPTY, 0, NULL, NULL,
|
|
NO_COLS_OWNED_BY_PROV, DBPARAMIO_NOTPARAM,
|
|
m_fBindLongCols),S_OK);
|
|
|
|
//Verify the data is correctly brought back using accessors
|
|
TESTC_(UseRowAccessorAndVerify(m_hAccessor, m_cbRowSize, g_uiRowNum,
|
|
m_rgTableColOrds, cCols, m_rgBindings, m_cBindings),S_OK);
|
|
|
|
//Check first accessor with GetBindings
|
|
TESTC(VerifyBindings(m_pIAccessor, m_rgBindings, m_cBindings, m_hAccessor,
|
|
DBACCESSOR_ROWDATA));
|
|
|
|
|
|
fSuccess = TRUE;
|
|
|
|
|
|
CLEANUP:
|
|
|
|
if (m_hAccessor)
|
|
{
|
|
m_pIAccessor->ReleaseAccessor(m_hAccessor, NULL);
|
|
m_hAccessor = DB_NULL_HACCESSOR;
|
|
}
|
|
|
|
FREE_BINDINGS(&m_cBindings, &m_rgBindings);
|
|
|
|
if (fSuccess)
|
|
return TEST_PASS;
|
|
else
|
|
return TEST_FAIL;
|
|
|
|
}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(15)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc Variable types bound BY_REF, without DBMEMOWNER_PROVIDEROWNED
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCCreateValidRowAccessors::Variation_15()
|
|
{
|
|
BOOL fSuccess = FALSE;
|
|
DBORDINAL cCols;
|
|
|
|
//Get accessor with variable data type cols bound BY_REF
|
|
TESTC_(GetAccessorAndBindings(m_pIAccessor,
|
|
DBACCESSOR_ROWDATA,
|
|
&m_hAccessor, &m_rgBindings, &m_cBindings, &m_cbRowSize,
|
|
DBPART_LENGTH | DBPART_STATUS | DBPART_VALUE,
|
|
ALL_COLS_BOUND, FORWARD, VARIABLE_LEN_COLS_BY_REF, NULL, &cCols,
|
|
NULL, DBTYPE_EMPTY, 0, NULL, NULL,
|
|
NO_COLS_OWNED_BY_PROV, DBPARAMIO_NOTPARAM, m_fBindLongCols),S_OK);
|
|
|
|
//Verify the data is correctly brought back using accessors
|
|
TESTC_(UseRowAccessorAndVerify(m_hAccessor, m_cbRowSize, g_uiRowNum,
|
|
m_rgTableColOrds, cCols, m_rgBindings, m_cBindings),S_OK);
|
|
|
|
//Check first accessor with GetBindings
|
|
TESTC(VerifyBindings(m_pIAccessor, m_rgBindings, m_cBindings, m_hAccessor,
|
|
DBACCESSOR_ROWDATA));
|
|
|
|
fSuccess = TRUE;
|
|
|
|
|
|
CLEANUP:
|
|
|
|
if (m_hAccessor)
|
|
{
|
|
m_pIAccessor->ReleaseAccessor(m_hAccessor, NULL);
|
|
m_hAccessor = DB_NULL_HACCESSOR;
|
|
}
|
|
|
|
FREE_BINDINGS(&m_cBindings, &m_rgBindings);
|
|
|
|
if (fSuccess)
|
|
return TEST_PASS;
|
|
else
|
|
return TEST_FAIL;
|
|
|
|
}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(16)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc All types bound BY_REF, with DBMEMOWNER_PROVIDEROWNED
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCCreateValidRowAccessors::Variation_16()
|
|
{
|
|
BOOL fSuccess = FALSE;
|
|
HRESULT hr = E_FAIL;
|
|
|
|
//Get accessor with all cols BY_REF and owned by provider
|
|
hr = GetAccessorAndBindings(m_pIAccessor,
|
|
DBACCESSOR_ROWDATA,
|
|
&m_hAccessor, &m_rgBindings, &m_cBindings, &m_cbRowSize,
|
|
DBPART_LENGTH | DBPART_STATUS | DBPART_VALUE,
|
|
ALL_COLS_BOUND, FORWARD, SUPPORTED_COLS_BY_REF, NULL,
|
|
NULL, NULL, DBTYPE_EMPTY, 0, NULL, NULL,
|
|
SUPPORTED_COLS_OWNED_BY_PROV, DBPARAMIO_NOTPARAM, m_fBindLongCols);
|
|
|
|
// It is now legal for providers not to support provider-owned memory. At a later time a
|
|
// property will be added to indicate support but at this time it's just DB_E_ERRORSOCCURRED.
|
|
if (hr == DB_E_ERRORSOCCURRED)
|
|
{
|
|
FREE_BINDINGS(&m_cBindings, &m_rgBindings);
|
|
odtLog << L"Couldn't create an accessor with provider-owned memory.\n";
|
|
return TEST_SKIPPED;
|
|
}
|
|
|
|
TESTC_(hr, S_OK);
|
|
|
|
//Verify the data is correctly brought back using accessors
|
|
TESTC_(UseRowAccessorAndVerify(m_hAccessor, m_cbRowSize, g_uiRowNum,
|
|
m_rgTableColOrds, m_cBindings, m_rgBindings, m_cBindings),S_OK);
|
|
|
|
//Check first accessor with GetBindings
|
|
TESTC(VerifyBindings(m_pIAccessor, m_rgBindings, m_cBindings, m_hAccessor,
|
|
DBACCESSOR_ROWDATA));
|
|
|
|
fSuccess = TRUE;
|
|
|
|
CLEANUP:
|
|
|
|
if (m_hAccessor)
|
|
{
|
|
m_pIAccessor->ReleaseAccessor(m_hAccessor, NULL);
|
|
m_hAccessor = DB_NULL_HACCESSOR;
|
|
}
|
|
|
|
FREE_BINDINGS(&m_cBindings, &m_rgBindings);
|
|
|
|
if (fSuccess)
|
|
return TEST_PASS;
|
|
else
|
|
return TEST_FAIL;
|
|
|
|
}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(17)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc Fixed types bound BY_REF, with DBMEMOWNER_PROVIDEROWNED
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCCreateValidRowAccessors::Variation_17()
|
|
{
|
|
//This is no longer a valid variation, CreateAccessor should fail
|
|
//for this scenario, and another variation covers this error condition
|
|
odtLog << L"No longer a valid variation. Left as a placeholder.\n";
|
|
return TEST_SKIPPED;
|
|
|
|
}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(18)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc Variable types bound BY_REF, with DBMEMOWNER_PROVIDEROWNED
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCCreateValidRowAccessors::Variation_18()
|
|
{
|
|
BOOL fSuccess = FALSE;
|
|
DBCOLUMNINFO * rgColInfo = NULL;
|
|
DBORDINAL cCols = 0;
|
|
ULONG i,j;
|
|
DBBINDSTATUS * rgStatus = NULL;
|
|
ULONG cFoundLongCols = 0;
|
|
OLECHAR * pStringsBuffer = NULL;
|
|
IColumnsInfo * pIColInfo = NULL;
|
|
HRESULT hr;
|
|
|
|
//Get accessor with variable data type cols bound BY_REF
|
|
//and all columns provider owned -- do not bind long columns.
|
|
hr = GetAccessorAndBindings(m_pIAccessor,
|
|
DBACCESSOR_ROWDATA,
|
|
&m_hAccessor, &m_rgBindings, &m_cBindings, &m_cbRowSize,
|
|
DBPART_LENGTH | DBPART_STATUS | DBPART_VALUE,
|
|
VARIABLE_LEN_COLS_BOUND, FORWARD, VARIABLE_LEN_COLS_BY_REF, NULL, NULL,
|
|
NULL, DBTYPE_EMPTY, 0, NULL, NULL,
|
|
SUPPORTED_COLS_OWNED_BY_PROV, DBPARAMIO_NOTPARAM, NO_BLOB_COLS);
|
|
|
|
|
|
// Some providers may not support variable length columns, in which case m_cBindings = 0.
|
|
// The accessor created will be a NULL accessor if such is supported, otherwise hr will be
|
|
// DB_E_NULLACCESSORNOTSUPPORTED.
|
|
if(m_cBindings == 0 && hr==DB_E_NULLACCESSORNOTSUPPORTED)
|
|
return TEST_SKIPPED;
|
|
|
|
// It is now legal for providers not to support provider-owned memory. At a later time a
|
|
// property will be added to indicate support but at this time it's just DB_E_ERRORSOCCURRED.
|
|
if (hr == DB_E_ERRORSOCCURRED)
|
|
{
|
|
FREE_BINDINGS(&m_cBindings, &m_rgBindings);
|
|
odtLog << L"Couldn't create an accessor with provider-owned memory.\n";
|
|
return TEST_SKIPPED;
|
|
}
|
|
|
|
// Any other case should be successful
|
|
TESTC_(hr, S_OK);
|
|
|
|
//Verify the data is correctly brought back using accessors
|
|
TESTC_(UseRowAccessorAndVerify(m_hAccessor, m_cbRowSize, g_uiRowNum,
|
|
m_rgTableColOrds, m_cRowsetCols, m_rgBindings, m_cBindings),S_OK);
|
|
|
|
//Check first accessor with GetBindings
|
|
TESTC(VerifyBindings(m_pIAccessor, m_rgBindings, m_cBindings, m_hAccessor,
|
|
DBACCESSOR_ROWDATA));
|
|
|
|
//Since long columns are illegal for provider owned memory,
|
|
//try it here
|
|
if (m_fBindLongCols == BLOB_LONG)
|
|
{
|
|
|
|
//clean up from last call
|
|
|
|
if (m_hAccessor)
|
|
{
|
|
m_pIAccessor->ReleaseAccessor(m_hAccessor, NULL);
|
|
m_hAccessor = DB_NULL_HACCESSOR;
|
|
}
|
|
|
|
FREE_BINDINGS(&m_cBindings, &m_rgBindings);
|
|
|
|
//Just get the bindings for long columns, don't specify MemOwner yet
|
|
//since then this function will fail
|
|
TESTC_(GetAccessorAndBindings(m_pIAccessor,
|
|
DBACCESSOR_ROWDATA,
|
|
&m_hAccessor, &m_rgBindings, &m_cBindings, &m_cbRowSize,
|
|
DBPART_LENGTH | DBPART_STATUS | DBPART_VALUE,
|
|
VARIABLE_LEN_COLS_BOUND, FORWARD, VARIABLE_LEN_COLS_BY_REF, NULL, NULL,
|
|
NULL, DBTYPE_EMPTY, 0, NULL, NULL,
|
|
NO_COLS_OWNED_BY_PROV, DBPARAMIO_NOTPARAM, m_fBindLongCols), S_OK);
|
|
|
|
//We only wanted the bindings
|
|
if (m_hAccessor)
|
|
{
|
|
m_pIAccessor->ReleaseAccessor(m_hAccessor, NULL);
|
|
m_hAccessor = DB_NULL_HACCESSOR;
|
|
}
|
|
|
|
//Make all possible bindings provider owned
|
|
AdjustMemOwner(DBMEMOWNER_PROVIDEROWNED, m_cBindings, m_rgBindings);
|
|
|
|
//Get the col info
|
|
TESTC(VerifyInterface(m_pIAccessor, IID_IColumnsInfo, ROWSET_INTERFACE,(IUnknown **) &pIColInfo));
|
|
|
|
TESTC_(pIColInfo->GetColumnInfo(&cCols,
|
|
&rgColInfo, &pStringsBuffer), S_OK);
|
|
|
|
rgStatus = (DBBINDSTATUS *)m_pIMalloc->Alloc(m_cBindings * sizeof(DBBINDSTATUS));
|
|
|
|
TESTC(rgStatus != NULL);
|
|
|
|
//Now try create the accessor with long cols
|
|
m_hr = m_pIAccessor->CreateAccessor(DBACCESSOR_ROWDATA, m_cBindings,
|
|
m_rgBindings, m_cbRowSize, &m_hAccessor, rgStatus);
|
|
|
|
//Make sure that each binding has the correct status
|
|
for (i=0; i<m_cBindings; i++)
|
|
{
|
|
//Loop thru the colinfo...
|
|
for (j=0; j<cCols; j++)
|
|
{
|
|
|
|
//...looking for the one which matches this binding
|
|
if (m_rgBindings[i].iOrdinal == rgColInfo[j].iOrdinal)
|
|
{
|
|
//Long data is invalid
|
|
if (rgColInfo[j].dwFlags & DBCOLUMNFLAGS_ISLONG)
|
|
{
|
|
if (S_OK != m_hr)
|
|
COMPARE(rgStatus[i], DBBINDSTATUS_BADBINDINFO);
|
|
else
|
|
COMPARE(rgStatus[i], DBBINDSTATUS_OK);
|
|
|
|
//Mark that we found at least one long col
|
|
cFoundLongCols++;
|
|
}
|
|
else
|
|
//Everything else should be fine
|
|
COMPARE(rgStatus[i], DBBINDSTATUS_OK);
|
|
|
|
|
|
//We found our colinfo for this binding, so stop looking
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
//Now check our return code
|
|
if (cFoundLongCols)
|
|
{
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
// ODBC Provider SPECIFIC NOTE:
|
|
//
|
|
//Note that this will only fail if the accessor is invalid for SetData as well;
|
|
//Right now Provider Owned memory is allowed for SetData, thus another reason
|
|
//for invalid SetData must exist for the accessor creation to actually fail.
|
|
//On SQL Server, we bind some non updateable columns, so SetData fails, and
|
|
//GetData fails for the Provider Owned memory case we our testing. For Brazos,
|
|
//we don't bind any non updateable columns, so even though the GetData
|
|
//validation may fail, SetData is still valid, thus accessor creation succeeds.
|
|
//For this reason, this line will fail on Brazos, but succeed on SQL Server.
|
|
// TODO: Figure out a way to guarantee the SetData part of validation always
|
|
//fails w/o affecting GetData validation.
|
|
|
|
// This can succeed if the provider thinks it can support this on LONG cols.
|
|
if (S_OK != m_hr)
|
|
{
|
|
TESTC_(m_hr, DB_E_ERRORSOCCURRED);
|
|
}
|
|
else
|
|
{
|
|
// Try to use the accessor
|
|
|
|
//Verify the data is correctly brought back using accessors
|
|
TESTC_(UseRowAccessorAndVerify(m_hAccessor, m_cbRowSize, g_uiRowNum,
|
|
m_rgTableColOrds, m_cRowsetCols, m_rgBindings, m_cBindings),S_OK);
|
|
|
|
//Check first accessor with GetBindings
|
|
TESTC(VerifyBindings(m_pIAccessor, m_rgBindings, m_cBindings, m_hAccessor,
|
|
DBACCESSOR_ROWDATA));
|
|
}
|
|
}
|
|
else
|
|
TESTC_(m_hr, S_OK);
|
|
|
|
}
|
|
|
|
fSuccess = TRUE;
|
|
|
|
CLEANUP:
|
|
|
|
SAFE_RELEASE(pIColInfo);
|
|
|
|
if (m_hAccessor)
|
|
{
|
|
m_pIAccessor->ReleaseAccessor(m_hAccessor, NULL);
|
|
m_hAccessor = DB_NULL_HACCESSOR;
|
|
}
|
|
|
|
FREE_BINDINGS(&m_cBindings, &m_rgBindings);
|
|
PROVIDER_FREE(pStringsBuffer);
|
|
PROVIDER_FREE(rgColInfo);
|
|
PROVIDER_FREE(rgStatus);
|
|
|
|
if (fSuccess)
|
|
return TEST_PASS;
|
|
else
|
|
return TEST_FAIL;
|
|
|
|
}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(19)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc No types bound BY_REF, with DBMEMOWNER_PROVIDEROWNED
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCCreateValidRowAccessors::Variation_19()
|
|
{
|
|
//BSTRS are the only type which can be Provider Owned without being BYREF
|
|
//NOTE, ODBC Provider does not support BSTRS, so this
|
|
//variation is not applicable to ODBC Provider.
|
|
|
|
HRESULT hr = E_FAIL;
|
|
BOOL fSuccess = FALSE;
|
|
|
|
|
|
//Get accessor with no data type cols bound BY_REF --
|
|
//and all columns provider owned. The DBMEMOWNER_PROVIDEROWNED
|
|
//should be a no op.
|
|
hr = GetAccessorAndBindings(m_pIAccessor,
|
|
DBACCESSOR_ROWDATA,
|
|
&m_hAccessor, &m_rgBindings, &m_cBindings, &m_cbRowSize,
|
|
DBPART_LENGTH | DBPART_STATUS | DBPART_VALUE,
|
|
ALL_COLS_BOUND, FORWARD, NO_COLS_BY_REF, NULL, NULL,
|
|
NULL, DBTYPE_EMPTY, 0, NULL, NULL,
|
|
SUPPORTED_COLS_OWNED_BY_PROV, DBPARAMIO_NOTPARAM, m_fBindLongCols);
|
|
|
|
// It is now legal for providers not to support provider-owned memory. At a later time a
|
|
// property will be added to indicate support but at this time it's just DB_E_ERRORSOCCURRED.
|
|
if (hr == DB_E_ERRORSOCCURRED)
|
|
{
|
|
odtLog << L"Couldn't create an accessor with provider-owned memory.\n";
|
|
return TEST_SKIPPED;
|
|
}
|
|
|
|
TESTC_(hr, S_OK);
|
|
|
|
//Verify the data is correctly brought back using accessors
|
|
TESTC_(UseRowAccessorAndVerify(m_hAccessor, m_cbRowSize, g_uiRowNum,
|
|
m_rgTableColOrds, m_cBindings, m_rgBindings, m_cBindings),S_OK);
|
|
|
|
//Check first accessor with GetBindings
|
|
TESTC(VerifyBindings(m_pIAccessor, m_rgBindings, m_cBindings, m_hAccessor,
|
|
DBACCESSOR_ROWDATA));
|
|
|
|
fSuccess = TRUE;
|
|
|
|
CLEANUP:
|
|
|
|
if (m_hAccessor)
|
|
{
|
|
m_pIAccessor->ReleaseAccessor(m_hAccessor, NULL);
|
|
m_hAccessor = DB_NULL_HACCESSOR;
|
|
}
|
|
if (m_rgBindings)
|
|
{
|
|
m_pIMalloc->Free(m_rgBindings);
|
|
m_rgBindings = NULL;
|
|
}
|
|
|
|
if (fSuccess)
|
|
return TEST_PASS;
|
|
else
|
|
return TEST_FAIL;
|
|
|
|
|
|
}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(20)
|
|
//--------------------------------------------------------------------
|
|
// @mfunc Use accessor after release rows
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCCreateValidRowAccessors::Variation_20()
|
|
{
|
|
BOOL fSuccess = FALSE;
|
|
DBCOUNTITEM cRowsObtained = 0;
|
|
HROW *pHRow = NULL;
|
|
HRESULT hr;
|
|
|
|
//Create Accessor
|
|
if (CHECK(GetAccessorAndBindings(m_pIAccessor, DBACCESSOR_ROWDATA,
|
|
&m_hAccessor, &m_rgBindings, &m_cBindings, &m_cbRowSize,
|
|
DBPART_STATUS|DBPART_LENGTH|DBPART_VALUE, ALL_COLS_BOUND,
|
|
FORWARD, NO_COLS_BY_REF, NULL, NULL,
|
|
NULL, DBTYPE_EMPTY, 0, NULL, NULL,
|
|
NO_COLS_OWNED_BY_PROV, DBPARAMIO_NOTPARAM,
|
|
m_fBindLongCols),S_OK))
|
|
{
|
|
// Make sure we're at the beginning of the rowset
|
|
// Some providers will need to re-execute the query to get back to the beginning
|
|
// so just check for success code. GetNextRows will return ENDOFROWSET if it fails.
|
|
if (!SUCCEEDED(hr = m_pIRowset->RestartPosition(NULL)))
|
|
CHECK(hr, S_OK);
|
|
|
|
if( CHECK(m_pIRowset->GetNextRows(NULL, 0, 1, &cRowsObtained, &pHRow), S_OK))
|
|
{
|
|
if( CHECK(m_pIRowset->ReleaseRows(cRowsObtained, pHRow, NULL, NULL, NULL), S_OK))
|
|
{
|
|
//Verify the data is correctly brought back using the accessor
|
|
//(via either GetData or ReadData).
|
|
if (CHECK(UseRowAccessorAndVerify(m_hAccessor, m_cbRowSize, g_uiRowNum,
|
|
m_rgTableColOrds, m_cRowsetCols, m_rgBindings, m_cBindings),S_OK))
|
|
//GetBindings should return same values we've used to create the accessor
|
|
fSuccess = VerifyBindings(m_pIAccessor, m_rgBindings, m_cBindings, m_hAccessor, DBACCESSOR_ROWDATA);
|
|
}
|
|
PROVIDER_FREE(pHRow);
|
|
}
|
|
}
|
|
//Clean up
|
|
if (m_hAccessor)
|
|
{
|
|
CHECK(m_pIAccessor->ReleaseAccessor(m_hAccessor, NULL), S_OK);
|
|
m_hAccessor = DB_NULL_HACCESSOR;
|
|
}
|
|
|
|
FREE_BINDINGS(&m_cBindings, &m_rgBindings);
|
|
|
|
if (fSuccess)
|
|
return TEST_PASS;
|
|
else
|
|
return TEST_FAIL;
|
|
}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(21)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc dwFlags: DBBINDFLAG_HTML
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCCreateValidRowAccessors::Variation_21()
|
|
{
|
|
|
|
BOOL fSuccess = TEST_FAIL;
|
|
BOOL fStringType = FALSE;
|
|
ULONG iBind;
|
|
DBBINDSTATUS * pBindStatus = NULL;
|
|
|
|
//Create Accessor with a binding using length, status and value
|
|
TESTC_(GetAccessorAndBindings(m_pIAccessor,
|
|
DBACCESSOR_ROWDATA,
|
|
&m_hAccessor, &m_rgBindings, &m_cBindings, &m_cbRowSize,
|
|
DBPART_LENGTH | DBPART_STATUS | DBPART_VALUE,
|
|
ALL_COLS_BOUND, FORWARD, NO_COLS_BY_REF, NULL,
|
|
NULL, NULL, DBTYPE_EMPTY, 0, NULL, g_rgParamOrds,
|
|
NO_COLS_OWNED_BY_PROV, DBPARAMIO_INPUT, m_fBindLongCols,
|
|
&pBindStatus),S_OK);
|
|
|
|
// Release the accessor we got above so we can change the binding information
|
|
SAFE_RELEASE_ACCESSOR(m_pIAccessor, m_hAccessor);
|
|
|
|
// Set dwFlags to DBBINDFLAG_HTML for all string types.
|
|
for(iBind = 0; iBind < m_cBindings; iBind++)
|
|
{
|
|
if (IS_BASE_TYPE(m_rgBindings[iBind].wType, DBTYPE_STR) ||
|
|
IS_BASE_TYPE(m_rgBindings[iBind].wType, DBTYPE_WSTR))
|
|
{
|
|
m_rgBindings[iBind].dwFlags = DBBINDFLAG_HTML;
|
|
fStringType = TRUE;
|
|
}
|
|
}
|
|
|
|
if (!fStringType)
|
|
{
|
|
odtLog << L"No string types available to test.\n";
|
|
fSuccess = TEST_SKIPPED;
|
|
goto CLEANUP;
|
|
}
|
|
|
|
// Now recreate the accessor. Note specifying DBBINDFLAGS_HTML is legal even if provider
|
|
// doesn't support it. It should be ignored.
|
|
TESTC_(m_pIAccessor->CreateAccessor(DBACCESSOR_ROWDATA, m_cBindings, m_rgBindings, m_cbRowSize,
|
|
&m_hAccessor, pBindStatus), S_OK);
|
|
|
|
//Verify the data is correctly brought back using the accessor
|
|
//(via either GetData or ReadData).
|
|
if(g_fCmdSupported)
|
|
{
|
|
CHECK(UseRowAccessorAndVerify(m_hAccessor, m_cbRowSize, g_uiRowNum,
|
|
m_rgTableColOrds, m_cRowsetCols, m_rgBindings, m_cBindings),S_OK);
|
|
}
|
|
|
|
//GetBindings should return same values we've used to create the accessor
|
|
TESTC(VerifyBindings(m_pIAccessor, m_rgBindings, m_cBindings, m_hAccessor,
|
|
DBACCESSOR_ROWDATA));
|
|
|
|
fSuccess = TEST_PASS;
|
|
|
|
CLEANUP:
|
|
|
|
//Clean up
|
|
SAFE_RELEASE_ACCESSOR(m_pIAccessor, m_hAccessor);
|
|
SAFE_FREE(pBindStatus);
|
|
FREE_BINDINGS(&m_cBindings, &m_rgBindings);
|
|
|
|
return fSuccess;
|
|
}
|
|
// }} TCW_VAR_PROTOTYPE_END
|
|
|
|
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(22)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc DBACCESSOR_INHERITED - Or'd with DBACCESSOR_OPTIMIZED
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCCreateValidRowAccessors::Variation_22()
|
|
{
|
|
BOOL fSuccess = FALSE;
|
|
DBORDINAL cCols;
|
|
DBORDINAL cCols2;
|
|
HRESULT hr;
|
|
HACCESSOR hCmdAccessor = DB_NULL_HACCESSOR;
|
|
HACCESSOR hAccInherited = m_hAccessor;
|
|
HACCESSOR hAccInherited2 = m_hAccessor2;
|
|
DBBINDSTATUS * pBindStatus;
|
|
DBBINDSTATUS * pBindStatus2;
|
|
DBACCESSORFLAGS dwFlags = DBACCESSOR_ROWDATA | DBACCESSOR_INHERITED;
|
|
DBACCESSORFLAGS dwFlags2 = dwFlags | DBACCESSOR_OPTIMIZED;
|
|
|
|
//Start with a clean rowset so optimized accessor creation is legal
|
|
ReleaseRowsetObject();
|
|
SAFE_RELEASE(m_pIRowset);
|
|
|
|
TESTC_(CreateRowsetObject(SELECT_VALIDATIONORDER), S_OK);
|
|
|
|
if(!VerifyInterface(m_pIAccessor,IID_IRowset, ROWSET_INTERFACE,
|
|
(IUnknown **)&m_pIRowset))
|
|
return TEST_FAIL;
|
|
|
|
//Create an optmized accessor, using odd columns
|
|
TESTC_(GetAccessorAndBindings(m_pIAccessor,
|
|
DBACCESSOR_ROWDATA | DBACCESSOR_OPTIMIZED,
|
|
&m_hAccessor, &m_rgBindings, &m_cBindings, &m_cbRowSize,
|
|
DBPART_LENGTH | DBPART_STATUS | DBPART_VALUE,
|
|
ODD_COLS_BOUND, FORWARD, NO_COLS_BY_REF, NULL, &cCols,
|
|
NULL, DBTYPE_EMPTY, 0, NULL, NULL,
|
|
NO_COLS_OWNED_BY_PROV, DBPARAMIO_NOTPARAM,
|
|
m_fBindLongCols),S_OK);
|
|
|
|
//Create a non optimized accessor using different columns (even ones)
|
|
TESTC_(GetAccessorAndBindings(m_pIAccessor, DBACCESSOR_ROWDATA,
|
|
&m_hAccessor2, &m_rgBindings2, &m_cBindings2, &m_cbRowSize2,
|
|
DBPART_LENGTH | DBPART_STATUS | DBPART_VALUE,
|
|
EVEN_COLS_BOUND, FORWARD, NO_COLS_BY_REF, NULL, &cCols2,
|
|
NULL, DBTYPE_EMPTY, 0, NULL, NULL,
|
|
NO_COLS_OWNED_BY_PROV, DBPARAMIO_NOTPARAM,
|
|
m_fBindLongCols),S_OK);
|
|
|
|
//This should be the same number since its the same rowset
|
|
TESTC(cCols==cCols2);
|
|
|
|
// Specify the input arguments - the original accessor handles
|
|
hAccInherited = m_hAccessor;
|
|
hAccInherited2 = m_hAccessor2;
|
|
|
|
// Allocate memory for DBBINDSTATUS arrays
|
|
SAFE_ALLOC(pBindStatus, DBSTATUS, m_cBindings);
|
|
SAFE_ALLOC(pBindStatus2, DBSTATUS, m_cBindings2);
|
|
|
|
// Now create new accessors specifying DBACCESSOR_INHERITED flag. Note that phAccessor
|
|
// is an input argument.
|
|
hr = m_pIAccessor->CreateAccessor(dwFlags, m_cBindings2, m_rgBindings2, m_cbRowSize2,
|
|
&hAccInherited2, pBindStatus2);
|
|
|
|
// If the provider doesn't support inherited accessors then DB_E_BADACCESSORFLAGS is expected.
|
|
if (DB_E_BADACCESSORFLAGS == hr)
|
|
{
|
|
odtLog << L"Provider does not support DBACCESSOR_INHERITED flag.\n";
|
|
|
|
// Make sure original accessors still work
|
|
hAccInherited = m_hAccessor;
|
|
hAccInherited2 = m_hAccessor2;
|
|
m_hAccessor = DB_NULL_HACCESSOR;
|
|
m_hAccessor2 = DB_NULL_HACCESSOR;
|
|
dwFlags &= ~DBACCESSOR_INHERITED;
|
|
dwFlags2 &= ~DBACCESSOR_INHERITED;
|
|
hr = S_OK;
|
|
}
|
|
else
|
|
TESTC_(m_pIAccessor->CreateAccessor (dwFlags2, m_cBindings, m_rgBindings,
|
|
m_cbRowSize, &hAccInherited, pBindStatus), S_OK);
|
|
|
|
TESTC_(hr, S_OK);
|
|
|
|
//Verify the data is correctly brought back using both accessors
|
|
//(via either GetData or ReadData).
|
|
TESTC_(UseRowAccessorAndVerify(hAccInherited, m_cbRowSize, g_uiRowNum,
|
|
m_rgTableColOrds, cCols, m_rgBindings, m_cBindings,
|
|
FALSE, TRUE),S_OK); //Keep same rows to be gotten by next call
|
|
|
|
TESTC_(UseRowAccessorAndVerify(hAccInherited2, m_cbRowSize2, g_uiRowNum,
|
|
m_rgTableColOrds, cCols2, m_rgBindings2, m_cBindings2),S_OK);
|
|
|
|
//Check first accessor with GetBindings
|
|
VerifyBindings(m_pIAccessor, m_rgBindings, m_cBindings, hAccInherited,
|
|
dwFlags2);
|
|
|
|
//Check second accessor with GetBindings
|
|
VerifyBindings(m_pIAccessor, m_rgBindings2, m_cBindings2, hAccInherited2,
|
|
dwFlags);
|
|
|
|
//We have to clean up since we kept the row in UseRowAccessorAndVerify
|
|
if(m_hRow && m_fIRowset)
|
|
{
|
|
m_pIRowset->ReleaseRows(m_cRowsObtained,&m_hRow,NULL, NULL,NULL);
|
|
m_hRow = DB_NULL_HROW;
|
|
}
|
|
|
|
fSuccess = TRUE;
|
|
|
|
CLEANUP:
|
|
|
|
//Clean Up
|
|
SAFE_RELEASE_ACCESSOR(m_pIAccessor, hAccInherited);
|
|
SAFE_RELEASE_ACCESSOR(m_pIAccessor, hAccInherited2);
|
|
SAFE_RELEASE_ACCESSOR(m_pIAccessor, m_hAccessor);
|
|
SAFE_RELEASE_ACCESSOR(m_pIAccessor, m_hAccessor2);
|
|
|
|
SAFE_FREE(pBindStatus);
|
|
SAFE_FREE(pBindStatus2);
|
|
|
|
FREE_BINDINGS(&m_cBindings, &m_rgBindings);
|
|
FREE_BINDINGS(&m_cBindings2, &m_rgBindings2);
|
|
|
|
//Make it clear to other variations that hRow is invalid
|
|
m_hRow = DB_NULL_HROW;
|
|
|
|
return fSuccess;
|
|
}
|
|
// }} TCW_VAR_PROTOTYPE_END
|
|
|
|
|
|
// {{ TCW_TERMINATE_METHOD
|
|
//--------------------------------------------------------------------
|
|
// @mfunc TestCase Termination Routine
|
|
//
|
|
// @rdesc TRUE or FALSE
|
|
//
|
|
BOOL TCCreateValidRowAccessors::Terminate()
|
|
{
|
|
PROVIDER_FREE(m_pDBPropSet);
|
|
PROVIDER_FREE(m_prgDBProps);
|
|
|
|
//Release the interface we allocated in Init
|
|
SAFE_RELEASE(m_pIRowset);
|
|
ReleaseRowsetObject();
|
|
|
|
// {{ TCW_TERM_BASECLASS_CHECK2
|
|
return(CAccessor::Terminate());
|
|
} // }}
|
|
// }}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_TC_PROTOTYPE(TCCreateValidParamAccessors)
|
|
//*-----------------------------------------------------------------------
|
|
//| Test Case: TCCreateValidParamAccessors - Creation of valid parameter accessors
|
|
//| Created: 11/11/95
|
|
//*-----------------------------------------------------------------------
|
|
|
|
//--------------------------------------------------------------------
|
|
// @mfunc TestCase Initialization Routine
|
|
//
|
|
// @rdesc TRUE or FALSE
|
|
//
|
|
BOOL TCCreateValidParamAccessors::Init()
|
|
{
|
|
IColumnsInfo * pIColumnsInfo = NULL;
|
|
ICommandPrepare * pICommandPrepare = NULL;
|
|
BOOL fResult = TEST_FAIL;
|
|
CCol TempCol(m_pIMalloc);
|
|
ULONG i, iSearchable;
|
|
DBORDINAL cColumns;
|
|
DBCOLUMNINFO * pColumnInfo = NULL;
|
|
WCHAR * pStringsBuffer = NULL;
|
|
|
|
// Initialize m_pSaveTable since it's used in Terminate.
|
|
m_pSaveTable = NULL;
|
|
|
|
//if command is not supported, skip this test.
|
|
if(!g_fCmdSupported)
|
|
{
|
|
odtLog << wszCommandNotSupported;
|
|
fResult = TEST_SKIPPED;
|
|
goto CLEANUP;
|
|
}
|
|
|
|
//if parameter accessor is not supported, skip this test.
|
|
if(!g_fParamAccessor)
|
|
{
|
|
odtLog << L"Parameter accessor is not supported."<<ENDL;
|
|
fResult = TEST_SKIPPED;
|
|
goto CLEANUP;
|
|
}
|
|
|
|
// {{ TCW_INIT_BASECLASS_CHECK
|
|
if(CAccessor::Init())
|
|
// }}
|
|
{
|
|
m_pSaveTable = m_pTable;
|
|
|
|
//Get a command object to generate parameterized queries on,
|
|
//and the rowset to find out what the columns will be
|
|
if (CHECK(CreateRowsetObject(SELECT_VALIDATIONORDER), S_OK))
|
|
{
|
|
|
|
//Create a table without using nulls because select fails on a null value.
|
|
m_pTable = new CTable((IUnknown *)m_pThisTestModule->m_pIUnknown2,
|
|
(LPWSTR)gwszModuleName, NONULLS);
|
|
|
|
if (!m_pTable)
|
|
{
|
|
odtLog << wszMemoryAllocationError;
|
|
goto CLEANUP;
|
|
}
|
|
|
|
TESTC_(m_pTable->CreateTable(0), S_OK);
|
|
|
|
//Determine what interface will be needed to retreive rows
|
|
//in UseParamAccessorAndVerify
|
|
if(VerifyInterface(m_pIAccessor,IID_IRowset, ROWSET_INTERFACE,
|
|
(IUnknown **)&m_pIRowset))
|
|
{
|
|
//Record that IRowset is supported
|
|
m_fIRowset = TRUE;
|
|
//Don't need interface
|
|
SAFE_RELEASE(m_pIRowset);
|
|
}
|
|
|
|
//Only need command after this
|
|
ReleaseRowsetObject();
|
|
|
|
/////////////////////////////////////////////////////////
|
|
// Build array containing col ordinals for all searchable
|
|
// cols so we can use them in parameterized queries
|
|
/////////////////////////////////////////////////////////
|
|
|
|
//Get memory to hold array of all col numbers. NOTE: This
|
|
//is the max possible, we won't necessarily use them all.
|
|
m_rgSearchableCols = (DB_LORDINAL *)m_pIMalloc->Alloc(m_pTable->CountColumnsOnTable() * sizeof(DB_LORDINAL));
|
|
if (!m_rgSearchableCols)
|
|
{
|
|
odtLog << wszMemoryAllocationError;
|
|
goto CLEANUP;
|
|
}
|
|
|
|
// While there is a searchable flag in CCol it is derived from IColumnsRowset and as
|
|
// such is not populated when using an ini file or if the provider doesn't support
|
|
// IColumnsRowset. So we'll use a select to give us the searchable colummns.
|
|
TESTC_(m_pTable->ExecuteCommand(SELECT_SEARCHABLE, IID_IRowset,
|
|
NULL, NULL, NULL, NULL, EXECUTE_NEVER,
|
|
0, NULL, NULL, NULL, &m_pICommand), S_OK);
|
|
|
|
// Get an IColumnsInfo interface
|
|
TESTC(VerifyInterface(m_pICommand,IID_IColumnsInfo, COMMAND_INTERFACE,
|
|
(IUnknown **)&pIColumnsInfo));
|
|
|
|
// If the provider supports Prepare we must before getting col info
|
|
if (VerifyInterface(m_pICommand,IID_ICommandPrepare, COMMAND_INTERFACE,
|
|
(IUnknown **)&pICommandPrepare))
|
|
{
|
|
TESTC_(pICommandPrepare->Prepare(1), S_OK);
|
|
}
|
|
|
|
TESTC_(pIColumnsInfo->GetColumnInfo(&cColumns, &pColumnInfo, &pStringsBuffer), S_OK);
|
|
|
|
//We'll use this count as the index to the array as we build it
|
|
m_cSearchableCols = 0;
|
|
|
|
// Look through the available columns in the table looking for searchable
|
|
// and updatable columns. We don't include LONG columns due to limitations
|
|
// of some providers.
|
|
for (i=1; i<=m_pTable->CountColumnsOnTable(); i++)
|
|
{
|
|
TESTC_(m_pTable->GetColInfo(i, TempCol), S_OK);
|
|
|
|
//Record the column number in the array
|
|
//if it is searchable
|
|
if (TempCol.GetIsLong())
|
|
continue;
|
|
|
|
if (TempCol.GetUpdateable())
|
|
{
|
|
// This is a candidate column, so we need to check searchability. If it's
|
|
// in the columns info obtained above then it's searchable.
|
|
|
|
/* Due to change in DBKIND reported by some providers just use the column name to identify
|
|
the column. This is a hack and is bad because it may not be the same as the base table
|
|
column name. The other choice would be to just use the name portion of the DBID which
|
|
should be the base table name, but then why have a guid portion if the name is always
|
|
sufficient?
|
|
for (iSearchable=0;
|
|
iSearchable < cColumns && !CompareDBID(pColumnInfo[iSearchable].columnid,
|
|
*TempCol.GetColID());
|
|
iSearchable++);
|
|
*/
|
|
for (iSearchable=0;
|
|
iSearchable < cColumns &&
|
|
pColumnInfo[iSearchable].pwszName &&
|
|
TempCol.GetColName() &&
|
|
wcscmp(pColumnInfo[iSearchable].pwszName,
|
|
TempCol.GetColName());
|
|
iSearchable++);
|
|
|
|
if (iSearchable < cColumns)
|
|
{
|
|
m_rgSearchableCols[m_cSearchableCols] = TempCol.GetColNum();
|
|
m_cSearchableCols++;
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
|
|
// When running with ini file we already have rows in the table
|
|
if (!GetModInfo()->GetFileName())
|
|
{
|
|
// Since this is a local table only to this test case lets insert both rows expected
|
|
// by the test case.
|
|
// Insert one row for Parameter Verification
|
|
TESTC_(m_pTable->InsertWithParams (g_uiRowNum), S_OK);
|
|
|
|
// Insert another row for Parameter Verification
|
|
TESTC_(m_pTable->InsertWithParams (g_uiRowNum + 1), S_OK);
|
|
}
|
|
|
|
//We've succeeded if we got this far
|
|
fResult = TRUE;
|
|
|
|
}
|
|
}
|
|
|
|
CLEANUP:
|
|
|
|
SAFE_FREE(pColumnInfo);
|
|
SAFE_FREE(pStringsBuffer);
|
|
SAFE_RELEASE(pIColumnsInfo);
|
|
SAFE_RELEASE(pICommandPrepare);
|
|
|
|
return fResult;
|
|
}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(1)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc ROWDATA and PARAMETERDATA accessor
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCCreateValidParamAccessors::Variation_1()
|
|
{
|
|
BOOL fSuccess = FALSE;
|
|
IAccessor * pCmdIAccessor = NULL;
|
|
|
|
#ifdef COMMAND_ACCESSOR_HACK
|
|
SAFE_RELEASE(m_pICommand);
|
|
TESTC_(m_pIDBCreateCommand->CreateCommand(NULL, IID_ICommand, (IUnknown **)&m_pICommand), S_OK);
|
|
#endif
|
|
|
|
//Get accessor interface on the command object on which we will do the execute
|
|
if (!VerifyInterface(m_pICommand, IID_IAccessor, COMMAND_INTERFACE,
|
|
(IUnknown **)&pCmdIAccessor))
|
|
goto CLEANUP;
|
|
|
|
//Just set the command so we can do IColumnsInfo to generate accessor
|
|
if (!CHECK(m_pTable->ExecuteCommand(SELECT_VALIDATIONORDER, IID_IRowset,
|
|
NULL, NULL, NULL, NULL, EXECUTE_NEVER,
|
|
0, NULL, NULL, NULL, &m_pICommand), S_OK))
|
|
goto CLEANUP;
|
|
|
|
//Create a ROWDATA and PARAMETERDATA accessor, using all cols
|
|
//so we can verify the rowdata portion on the rowset
|
|
if (!CHECK(GetAccessorAndBindings(pCmdIAccessor,
|
|
DBACCESSOR_ROWDATA | DBACCESSOR_PARAMETERDATA,
|
|
&m_hAccessor, &m_rgBindings, &m_cBindings, &m_cbRowSize,
|
|
DBPART_VALUE | DBPART_STATUS | DBPART_LENGTH,
|
|
ALL_COLS_BOUND, FORWARD, NO_COLS_BY_REF, NULL,
|
|
NULL, NULL, DBTYPE_EMPTY, 0, NULL, NULL,
|
|
NO_COLS_OWNED_BY_PROV, DBPARAMIO_INPUT,
|
|
m_fBindLongCols),S_OK))
|
|
goto CLEANUP;
|
|
|
|
//Execute the query to generate a rowset object for the rowdata accessor
|
|
if (!CHECK(m_hr = m_pTable->ExecuteCommand(SELECT_VALIDATIONORDER, IID_IRowset,
|
|
NULL, NULL, NULL, &m_rgTableColOrds, EXECUTE_ALWAYS,
|
|
0, NULL, NULL, (IUnknown **)&m_pIRowset, &m_pICommand), S_OK))
|
|
goto CLEANUP;
|
|
|
|
//Verify the data is correctly brought back using the accessor
|
|
if (!CHECK(UseRowAccessorAndVerify(m_hAccessor, m_cbRowSize, g_uiRowNum,
|
|
m_rgTableColOrds, m_pTable->CountColumnsOnTable(), m_rgBindings,
|
|
m_cBindings),S_OK))
|
|
goto CLEANUP;
|
|
|
|
if (!VerifyBindings(pCmdIAccessor, m_rgBindings, m_cBindings, m_hAccessor,
|
|
DBACCESSOR_ROWDATA | DBACCESSOR_PARAMETERDATA))
|
|
goto CLEANUP;
|
|
|
|
//Cleanup rowset so we can use command again
|
|
COMPARE(m_pIRowset->Release(), 0);
|
|
m_pIRowset = NULL;
|
|
FREE_BINDINGS(&m_cBindings, &m_rgBindings);
|
|
PROVIDER_FREE(m_rgTableColOrds);
|
|
|
|
//Release this so we can start with another accessor testing parameters
|
|
pCmdIAccessor->ReleaseAccessor(m_hAccessor, NULL);
|
|
m_hAccessor = DB_NULL_HACCESSOR;
|
|
|
|
//Now create a dual accessor, but use searchable columns
|
|
//and specify the right ordinals so we can use it for our
|
|
//parameterized statement
|
|
if (!CHECK(GetAccessorAndBindings(pCmdIAccessor,
|
|
DBACCESSOR_ROWDATA | DBACCESSOR_PARAMETERDATA,
|
|
&m_hAccessor, &m_rgBindings, &m_cBindings, &m_cbRowSize,
|
|
DBPART_VALUE | DBPART_STATUS | DBPART_LENGTH,
|
|
USE_COLS_TO_BIND_ARRAY, FORWARD, NO_COLS_BY_REF, NULL, NULL,
|
|
NULL, DBTYPE_EMPTY, m_cSearchableCols, m_rgSearchableCols,
|
|
g_rgParamOrds, NO_COLS_OWNED_BY_PROV, DBPARAMIO_INPUT,
|
|
m_fBindLongCols), S_OK))
|
|
goto CLEANUP;
|
|
|
|
if (!CHECK(UseParamAccessorAndVerify(m_hAccessor,
|
|
DBACCESSOR_ROWDATA | DBACCESSOR_PARAMETERDATA,
|
|
m_cbRowSize, g_uiRowNum, m_rgBindings, m_cBindings, m_pICommand),S_OK))
|
|
goto CLEANUP;
|
|
|
|
//Check accessor with GetBindings
|
|
fSuccess = VerifyBindings(pCmdIAccessor, m_rgBindings, m_cBindings, m_hAccessor,
|
|
DBACCESSOR_ROWDATA | DBACCESSOR_PARAMETERDATA);
|
|
|
|
|
|
CLEANUP:
|
|
|
|
if (m_hAccessor != DB_NULL_HACCESSOR)
|
|
{
|
|
pCmdIAccessor->ReleaseAccessor(m_hAccessor, NULL);
|
|
m_hAccessor = DB_NULL_HACCESSOR;
|
|
}
|
|
|
|
SAFE_RELEASE(m_pIRowset);
|
|
SAFE_RELEASE(pCmdIAccessor);
|
|
|
|
FREE_BINDINGS(&m_cBindings, &m_rgBindings);
|
|
PROVIDER_FREE(m_rgTableColOrds);
|
|
|
|
if (fSuccess)
|
|
return TEST_PASS;
|
|
else
|
|
return TEST_FAIL;
|
|
}
|
|
|
|
// }}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(2)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc Null Parameter Accessor
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCCreateValidParamAccessors::Variation_2()
|
|
{
|
|
BOOL fSuccess = FALSE;
|
|
ICommand * pICommand = NULL;
|
|
IRowset * pRowset = NULL;
|
|
|
|
|
|
//Get a command set to use parameters, have function return its new ICommand
|
|
if (!CHECK(m_pTable->ExecuteCommand(
|
|
SELECT_ALL_WITH_SEARCHABLE_AND_UPDATEABLE, //Parameterized query
|
|
IID_IAccessor, //We won't execute, this will be ignored
|
|
NULL, NULL, NULL, NULL, //Stuff we don't need since we aren't executing
|
|
EXECUTE_NEVER, //Only want to set the command
|
|
0, NULL, NULL, NULL, //More stuff we don't need
|
|
&pICommand //Want command object which was set
|
|
), S_OK))
|
|
goto CLEANUP;
|
|
|
|
|
|
//Get accessor interface on the set command object
|
|
if (!VerifyInterface(pICommand, IID_IAccessor, COMMAND_INTERFACE,
|
|
(IUnknown **)&m_pIAccessor))
|
|
goto CLEANUP;
|
|
|
|
//It is invalid to create a null accessor on a command object
|
|
fSuccess = CHECK(m_pIAccessor->CreateAccessor(DBACCESSOR_PARAMETERDATA, 0, NULL,
|
|
m_cbRowSize, &m_hAccessor, m_rgStatus),DB_E_NULLACCESSORNOTSUPPORTED);
|
|
|
|
|
|
CLEANUP:
|
|
|
|
SAFE_RELEASE(pICommand);
|
|
SAFE_RELEASE(m_pIAccessor);
|
|
|
|
if (fSuccess)
|
|
return TEST_PASS;
|
|
else
|
|
return TEST_FAIL;
|
|
|
|
}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(3)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc dwPart - DBCOLUMPART_VALUE
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCCreateValidParamAccessors::Variation_3()
|
|
{
|
|
BOOL fSuccess = FALSE;
|
|
CTable * pSaveTable = NULL;
|
|
ULONG i=0;
|
|
|
|
#ifdef COMMAND_ACCESSOR_HACK
|
|
SAFE_RELEASE(m_pICommand);
|
|
TESTC_(m_pIDBCreateCommand->CreateCommand(NULL, IID_ICommand, (IUnknown **)&m_pICommand), S_OK);
|
|
#endif
|
|
|
|
//Create a table that doesn't use nulls so we never need to
|
|
//use a parameter's status, since we won't bind it
|
|
pSaveTable = m_pTable;
|
|
m_pTable = new CTable((IUnknown *)m_pThisTestModule->m_pIUnknown2,
|
|
(LPWSTR)gwszModuleName, NONULLS);
|
|
if (!m_pTable)
|
|
{
|
|
odtLog << wszMemoryAllocationError;
|
|
goto CLEANUP;
|
|
}
|
|
|
|
if (FAILED(m_pTable->CreateTable(0)))
|
|
return FALSE;
|
|
|
|
//Insert one row based on the number all our routines will expect
|
|
//if (!CHECK(m_pTable->Insert(g_uiRowNum), S_OK))
|
|
if (!CHECK(m_pTable->InsertWithParams(g_uiRowNum), S_OK))
|
|
goto CLEANUP;
|
|
|
|
// Insert another row for Parameter Verification
|
|
if (!CHECK (m_pTable->InsertWithParams (g_uiRowNum + 1), S_OK))
|
|
goto CLEANUP;
|
|
|
|
//Get an accessor interface on our command object
|
|
if (!VerifyInterface(m_pICommand, IID_IAccessor, COMMAND_INTERFACE,
|
|
(IUnknown **)&m_pIAccessor))
|
|
goto CLEANUP;
|
|
|
|
//Just set the command so we can do IColumnsInfo to generate accessor
|
|
if (!CHECK(m_pTable->ExecuteCommand(SELECT_VALIDATIONORDER, IID_IRowset,
|
|
NULL, NULL, NULL, NULL, EXECUTE_NEVER,
|
|
0, NULL, NULL, NULL, &m_pICommand), S_OK))
|
|
goto CLEANUP;
|
|
|
|
//Create Accessor with a binding using only DBCOLUMPART_VALUE
|
|
if (!CHECK(GetAccessorAndBindings(m_pIAccessor, DBACCESSOR_PARAMETERDATA,
|
|
&m_hAccessor, &m_rgBindings, &m_cBindings, &m_cbRowSize,
|
|
DBPART_LENGTH | DBPART_STATUS | DBPART_VALUE, USE_COLS_TO_BIND_ARRAY, FORWARD, NO_COLS_BY_REF, NULL, NULL,
|
|
NULL, DBTYPE_EMPTY, m_cSearchableCols, m_rgSearchableCols,
|
|
g_rgParamOrds, NO_COLS_OWNED_BY_PROV, DBPARAMIO_INPUT,
|
|
m_fBindLongCols),S_OK))
|
|
goto CLEANUP;
|
|
|
|
|
|
// Fixup bindings now. It's generally an error to not bind the length for
|
|
// variable length types unless:
|
|
// For char types assume NULL terminated.
|
|
// For DBTYPE_BYTES assume length is cbMaxLen.
|
|
// For DBTYPE_VARNUMERIC assume length is cbMaxLength?
|
|
// This was changed recently in the spec.
|
|
for (i = 0; i < m_cBindings; i++ )
|
|
{
|
|
// Remove the length and status bindings
|
|
m_rgBindings[i].dwPart = 0| DBPART_VALUE;
|
|
}
|
|
|
|
// Recreate the accessor since we've changed the bindings
|
|
TESTC_(m_pIAccessor->ReleaseAccessor(m_hAccessor, NULL), S_OK);
|
|
TESTC_(m_pIAccessor->CreateAccessor(DBACCESSOR_PARAMETERDATA, m_cBindings, m_rgBindings, m_cbRowSize,
|
|
&m_hAccessor, NULL), S_OK);
|
|
|
|
|
|
//Verify parameter accessor can be used to successfully retrieve a row
|
|
//NOTE: We are assuming (since we didn't bind length) that cbMaxLen
|
|
//is equal to the correct data length, so the right length of values
|
|
//are used for the parameter.
|
|
if (!CHECK(UseParamAccessorAndVerify(m_hAccessor,
|
|
DBACCESSOR_PARAMETERDATA, m_cbRowSize, g_uiRowNum,
|
|
m_rgBindings, m_cBindings, m_pICommand),S_OK))
|
|
goto CLEANUP;
|
|
|
|
//GetBindings should return same values we've used to create the accessor
|
|
// Since we changed the bindings this will fail.
|
|
fSuccess = TRUE;
|
|
// fSuccess = VerifyBindings(m_pIAccessor, m_rgBindings, m_cBindings, m_hAccessor, DBACCESSOR_PARAMETERDATA);
|
|
|
|
CLEANUP :
|
|
|
|
if (m_pTable)
|
|
{
|
|
m_pTable->DropTable();
|
|
delete m_pTable;
|
|
}
|
|
|
|
//Set our table back to the default one for the whole test module
|
|
m_pTable = pSaveTable;
|
|
|
|
//Clean up
|
|
if (m_hAccessor)
|
|
{
|
|
m_pIAccessor->ReleaseAccessor(m_hAccessor, NULL);
|
|
m_hAccessor = DB_NULL_HACCESSOR;
|
|
}
|
|
|
|
SAFE_RELEASE(m_pIAccessor);
|
|
FREE_BINDINGS(&m_cBindings, &m_rgBindings);
|
|
|
|
if (fSuccess)
|
|
return TEST_PASS;
|
|
else
|
|
return TEST_FAIL;
|
|
|
|
}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(4)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc dwPart - DBCOLUMPART_LENGTH
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCCreateValidParamAccessors::Variation_4()
|
|
{
|
|
BOOL fSuccess = FALSE;
|
|
BYTE * pParamData = NULL;
|
|
ICommand * pICommand = NULL;
|
|
DBPARAMS Param;
|
|
IRowset * pRowset = NULL;
|
|
|
|
|
|
//Just set the command so we can do IColumnsInfo to generate accessor
|
|
if (!CHECK(m_pTable->ExecuteCommand(SELECT_VALIDATIONORDER, IID_IRowset,
|
|
NULL, NULL, NULL, NULL, EXECUTE_NEVER,
|
|
0, NULL, NULL, NULL, &pICommand), S_OK))
|
|
goto CLEANUP;
|
|
|
|
//Get accessor interface on the command object which is set
|
|
if (!VerifyInterface(pICommand, IID_IAccessor, COMMAND_INTERFACE,
|
|
(IUnknown **)&m_pIAccessor))
|
|
goto CLEANUP;
|
|
|
|
//Create parameter Accessor with a binding using only DBCOLUMPART_LENGTH
|
|
if (!CHECK(GetAccessorAndBindings(m_pIAccessor, DBACCESSOR_PARAMETERDATA,
|
|
&m_hAccessor, &m_rgBindings, &m_cBindings, &m_cbRowSize,
|
|
DBPART_LENGTH, USE_COLS_TO_BIND_ARRAY, FORWARD, NO_COLS_BY_REF, NULL, NULL,
|
|
NULL, DBTYPE_EMPTY, m_cSearchableCols, m_rgSearchableCols,
|
|
g_rgParamOrds, NO_COLS_OWNED_BY_PROV, DBPARAMIO_INPUT, m_fBindLongCols),S_OK))
|
|
goto CLEANUP;
|
|
|
|
//Have function generate a new command object and set it with parameterized query
|
|
if (!CHECK(m_pTable->ExecuteCommand(
|
|
SELECT_ALL_WITH_SEARCHABLE_AND_UPDATEABLE, //Parameterized query
|
|
IID_IAccessor, //We won't execute, this will be ignored
|
|
NULL, NULL, NULL, NULL, //Stuff we don't need since we aren't executing
|
|
EXECUTE_NEVER, //Only want to set the command
|
|
0, NULL, NULL, NULL, //More stuff we don't need
|
|
&pICommand //Want command object which was set
|
|
), S_OK))
|
|
goto CLEANUP;
|
|
|
|
|
|
pParamData = (BYTE *)m_pIMalloc->Alloc(m_cbRowSize);
|
|
if (!pParamData)
|
|
goto CLEANUP;
|
|
|
|
//Set up our buffer to only have length bound
|
|
if (!CHECK(FillInputBindings(m_pTable,
|
|
DBACCESSOR_PARAMETERDATA, m_cBindings, m_rgBindings, &pParamData, g_uiRowNum,
|
|
m_cSearchableCols, m_rgSearchableCols, PRIMARY), S_OK))
|
|
goto CLEANUP;
|
|
|
|
//Set up parameters to use the accessor
|
|
Param.cParamSets = 1;
|
|
Param.hAccessor = m_hAccessor;
|
|
Param.pData = (BYTE *)pParamData;
|
|
|
|
//Verify that since we didn't set any default params,
|
|
//using an accessor with only length bound should fail
|
|
fSuccess = CHECK(pICommand->Execute(NULL, IID_IAccessor, &Param,
|
|
NULL, (IUnknown **)&pRowset), DB_E_ERRORSOCCURRED);
|
|
|
|
|
|
CLEANUP:
|
|
PROVIDER_FREE(pParamData);
|
|
FREE_BINDINGS(&m_cBindings, &m_rgBindings);
|
|
|
|
if (m_hAccessor)
|
|
{
|
|
m_pIAccessor->ReleaseAccessor(m_hAccessor, NULL);
|
|
m_hAccessor = DB_NULL_HACCESSOR;
|
|
}
|
|
|
|
SAFE_RELEASE(m_pIAccessor);
|
|
SAFE_RELEASE(pICommand);
|
|
|
|
if (fSuccess)
|
|
return TEST_PASS;
|
|
else
|
|
return TEST_FAIL;
|
|
|
|
}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(5)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc dwPart - DBCOLUMPART_STATUS
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCCreateValidParamAccessors::Variation_5()
|
|
{
|
|
BOOL fSuccess = FALSE;
|
|
BYTE * pParamData = NULL;
|
|
ICommand * pICommand = NULL;
|
|
DBPARAMS Param;
|
|
IRowset * pRowset = NULL;
|
|
ULONG iIndex = 0;
|
|
ULONG i=0;
|
|
CCol TempCol;
|
|
|
|
//Just set the command so we can do IColumnsInfo to generate accessor
|
|
if (!CHECK(m_pTable->ExecuteCommand(SELECT_VALIDATIONORDER, IID_IRowset,
|
|
NULL, NULL, NULL, NULL, EXECUTE_NEVER,
|
|
0, NULL, NULL, NULL, &pICommand), S_OK))
|
|
goto CLEANUP;
|
|
|
|
|
|
//Get accessor interface on the command object which is set
|
|
if (!VerifyInterface(pICommand, IID_IAccessor, COMMAND_INTERFACE,
|
|
(IUnknown **)&m_pIAccessor))
|
|
goto CLEANUP;
|
|
|
|
// Create parameter Accessor with a binding using only DBCOLUMPART_STATUS
|
|
// Currently Set to DBPART_ALL but later change to only DBPART_STATUS
|
|
// This is done so that first we use FillINputBindings for all the bindings
|
|
// and convert bindings for which columns are nullable to DBSTATUS_S_ISNULL and binding to DBPART_STATUS only.
|
|
|
|
if (!CHECK(GetAccessorAndBindings(m_pIAccessor, DBACCESSOR_PARAMETERDATA,
|
|
&m_hAccessor, &m_rgBindings, &m_cBindings, &m_cbRowSize,
|
|
DBPART_VALUE | DBPART_LENGTH | DBPART_STATUS, USE_COLS_TO_BIND_ARRAY, FORWARD, NO_COLS_BY_REF, NULL, NULL,
|
|
NULL, DBTYPE_EMPTY, m_cSearchableCols, m_rgSearchableCols,
|
|
g_rgParamOrds, NO_COLS_OWNED_BY_PROV, DBPARAMIO_INPUT,
|
|
m_fBindLongCols), S_OK))
|
|
goto CLEANUP;
|
|
|
|
//Have function generate a new command object and set it with parameterized query
|
|
if (!CHECK(m_pTable->ExecuteCommand(
|
|
SELECT_ALL_WITH_SEARCHABLE_AND_UPDATEABLE, //Parameterized query
|
|
IID_IAccessor, //We won't execute, this will be ignored
|
|
NULL, NULL, NULL, NULL, //Stuff we don't need since we aren't executing
|
|
EXECUTE_NEVER, //Only want to set the command
|
|
0, NULL, NULL, NULL, //More stuff we don't need
|
|
&pICommand //Want command object which was set
|
|
), S_OK))
|
|
goto CLEANUP;
|
|
|
|
pParamData = (BYTE *)m_pIMalloc->Alloc(m_cbRowSize);
|
|
if (!pParamData)
|
|
goto CLEANUP;
|
|
|
|
|
|
//Set up our buffer to only have length bound
|
|
if (!CHECK(FillInputBindings(m_pTable,
|
|
DBACCESSOR_PARAMETERDATA, m_cBindings, m_rgBindings, &pParamData, g_uiRowNum,
|
|
m_cSearchableCols, m_rgSearchableCols, PRIMARY), S_OK))
|
|
goto CLEANUP;
|
|
|
|
// Now the bindings of nullable columns to DBPART_STATUS and set the status bit appropriately for them.
|
|
for (i = 1; i <= m_pTable->CountColumnsOnTable(); i++)
|
|
{
|
|
CHECK(m_pTable->GetColInfo(i, TempCol), S_OK);
|
|
|
|
//Record the column number in the array
|
|
//if it is
|
|
//Record the column number in the array
|
|
//if it is searchable
|
|
if (TempCol.GetIsLong())
|
|
continue;
|
|
|
|
if (TempCol.GetUpdateable() && (TempCol.GetSearchable() != DB_UNSEARCHABLE))
|
|
{
|
|
|
|
ASSERT(iIndex < m_cBindings);
|
|
|
|
if (TempCol.GetNullable() == TRUE )
|
|
{
|
|
m_rgBindings[iIndex].dwPart = 0| DBPART_STATUS;
|
|
// Set pData to DBSTATUS_ISNULL;
|
|
*((DBSTATUS *)((BYTE *)pParamData + m_rgBindings[iIndex].obStatus)) = DBSTATUS_S_ISNULL;
|
|
|
|
}
|
|
iIndex++; // For updateable Column.
|
|
}
|
|
|
|
}
|
|
|
|
//Set up parameters to use the accessor
|
|
Param.cParamSets = 1;
|
|
Param.hAccessor = m_hAccessor;
|
|
Param.pData = (BYTE *)pParamData;
|
|
|
|
//Verify that query was executed successfully, even though no rows should be found
|
|
// TODO
|
|
|
|
fSuccess = CHECK(pICommand->Execute(NULL, IID_IAccessor, &Param,
|
|
NULL, (IUnknown **)&pRowset),S_OK);
|
|
|
|
|
|
CLEANUP:
|
|
SAFE_RELEASE(pRowset);
|
|
|
|
PROVIDER_FREE(pParamData);
|
|
FREE_BINDINGS(&m_cBindings, &m_rgBindings);
|
|
|
|
if (m_hAccessor)
|
|
{
|
|
m_pIAccessor->ReleaseAccessor(m_hAccessor, NULL);
|
|
m_hAccessor = DB_NULL_HACCESSOR;
|
|
}
|
|
SAFE_RELEASE(m_pIAccessor);
|
|
SAFE_RELEASE(pICommand);
|
|
|
|
if (fSuccess)
|
|
return TEST_PASS;
|
|
else
|
|
return TEST_FAIL;
|
|
|
|
}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(6)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc dwPart - DBCOLUMPART_VALUE | DBPART_STATUS
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCCreateValidParamAccessors::Variation_6()
|
|
{
|
|
BOOL fSuccess = FALSE;
|
|
ULONG i=0;
|
|
|
|
//Just set the command so we can do IColumnsInfo to generate accessor
|
|
if (!CHECK(m_pTable->ExecuteCommand(SELECT_VALIDATIONORDER, IID_IRowset,
|
|
NULL, NULL, NULL, NULL, EXECUTE_NEVER,
|
|
0, NULL, NULL, NULL, &m_pICommand), S_OK))
|
|
goto CLEANUP;
|
|
|
|
//Get an accessor interface on our command object
|
|
if (!VerifyInterface(m_pICommand, IID_IAccessor, COMMAND_INTERFACE,
|
|
(IUnknown **)&m_pIAccessor))
|
|
goto CLEANUP;
|
|
|
|
//Create Accessor with a binding using only DBCOLUMPART_VALUE and STATUS.
|
|
//The length should be determined by cbMaxLen alone.
|
|
if (!CHECK(GetAccessorAndBindings(m_pIAccessor, DBACCESSOR_PARAMETERDATA,
|
|
&m_hAccessor, &m_rgBindings, &m_cBindings, &m_cbRowSize,
|
|
DBPART_LENGTH | DBPART_VALUE | DBPART_STATUS, USE_COLS_TO_BIND_ARRAY,
|
|
FORWARD, NO_COLS_BY_REF, NULL, NULL,
|
|
NULL, DBTYPE_EMPTY, m_cSearchableCols, m_rgSearchableCols,
|
|
g_rgParamOrds, NO_COLS_OWNED_BY_PROV, DBPARAMIO_INPUT,
|
|
m_fBindLongCols),S_OK))
|
|
goto CLEANUP;
|
|
|
|
// Fixup bindings now:
|
|
for (i = 0; i < m_cBindings; i++ )
|
|
{
|
|
// For variable length types the length is required, although this is under spec review.
|
|
// Bind only value and status for fixed length types and DBTYPE_BTYES. For DBTYPE_BYTES if
|
|
// the consumer doesn't bind length provider must get length from cbMaxLen.
|
|
if (IsFixedLength(m_rgBindings[i].wType) || DBTYPE_BYTES == m_rgBindings[i].wType)
|
|
// For rest remove the length bindings.
|
|
m_rgBindings[i].dwPart = DBPART_VALUE | DBPART_STATUS;
|
|
|
|
}
|
|
|
|
// Recreate the accessor since we've changed the bindings
|
|
TESTC_(m_pIAccessor->ReleaseAccessor(m_hAccessor, NULL), S_OK);
|
|
TESTC_(m_pIAccessor->CreateAccessor(DBACCESSOR_PARAMETERDATA, m_cBindings, m_rgBindings, m_cbRowSize,
|
|
&m_hAccessor, NULL), S_OK);
|
|
|
|
//Verify
|
|
if (!CHECK(UseParamAccessorAndVerify(m_hAccessor,
|
|
DBACCESSOR_PARAMETERDATA, m_cbRowSize, g_uiRowNum,
|
|
m_rgBindings, m_cBindings, m_pICommand),S_OK))
|
|
goto CLEANUP;
|
|
|
|
//GetBindings should return same values we've used to create the accessor
|
|
// Since we changed the bindings this will fail.
|
|
fSuccess = TRUE;
|
|
// fSuccess = VerifyBindings(m_pIAccessor, m_rgBindings, m_cBindings, m_hAccessor, DBACCESSOR_PARAMETERDATA);
|
|
|
|
CLEANUP :
|
|
|
|
//Clean up
|
|
if (m_hAccessor)
|
|
{
|
|
m_pIAccessor->ReleaseAccessor(m_hAccessor, NULL);
|
|
m_hAccessor = DB_NULL_HACCESSOR;
|
|
}
|
|
SAFE_RELEASE(m_pIAccessor);
|
|
FREE_BINDINGS(&m_cBindings, &m_rgBindings);
|
|
|
|
if (fSuccess)
|
|
return TEST_PASS;
|
|
else
|
|
return TEST_FAIL;
|
|
|
|
|
|
}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(7)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc dwPart - DBCOLUMPART_LENGTH | DBPART_STATUS | DBPART_VALUE
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCCreateValidParamAccessors::Variation_7()
|
|
{
|
|
BOOL fSuccess = FALSE;
|
|
ULONG ulBindIdx;
|
|
|
|
|
|
//Just set the command so we can do IColumnsInfo to generate accessor
|
|
if (!CHECK(m_pTable->ExecuteCommand(SELECT_VALIDATIONORDER, IID_IRowset,
|
|
NULL, NULL, NULL, NULL, EXECUTE_NEVER,
|
|
0, NULL, NULL, NULL, &m_pICommand), S_OK))
|
|
goto CLEANUP;
|
|
|
|
//Get an accessor interface on our command object
|
|
if (!VerifyInterface(m_pICommand, IID_IAccessor, COMMAND_INTERFACE,
|
|
(IUnknown **)&m_pIAccessor))
|
|
goto CLEANUP;
|
|
|
|
//Create Accessor with a binding using all three parts, DBCOLUMPART_VALUE, LENGTH and STATUS.
|
|
if (!CHECK(GetAccessorAndBindings(m_pIAccessor, DBACCESSOR_PARAMETERDATA,
|
|
&m_hAccessor, &m_rgBindings, &m_cBindings, &m_cbRowSize,
|
|
DBPART_LENGTH | DBPART_VALUE | DBPART_STATUS, USE_COLS_TO_BIND_ARRAY,
|
|
FORWARD, NO_COLS_BY_REF, NULL, NULL,
|
|
NULL, DBTYPE_EMPTY, m_cSearchableCols, m_rgSearchableCols,
|
|
g_rgParamOrds, NO_COLS_OWNED_BY_PROV, DBPARAMIO_INPUT,
|
|
m_fBindLongCols),S_OK))
|
|
goto CLEANUP;
|
|
|
|
//Set cbMaxLen to a number larger than the length bound will ever be,
|
|
//to ensure that the provider is not using cbMaxLen instead of length
|
|
//bound and thus reading past end of value
|
|
for (ulBindIdx=0; ulBindIdx<m_cBindings; ulBindIdx++)
|
|
m_rgBindings[ulBindIdx].cbMaxLen = MAX_COL_SIZE + 1;
|
|
|
|
//Verify
|
|
// TODO Fails to select. Execute execute success fully.
|
|
if (!CHECK(UseParamAccessorAndVerify(m_hAccessor,
|
|
DBACCESSOR_PARAMETERDATA, m_cbRowSize, g_uiRowNum,
|
|
m_rgBindings, m_cBindings, m_pICommand),S_OK))
|
|
goto CLEANUP;
|
|
|
|
fSuccess = TRUE;
|
|
//GetBindings should return same values we've used to create the accessor
|
|
// Since we changed the cbMaxLen this comparision fails.
|
|
//fSuccess = VerifyBindings(m_pIAccessor, m_rgBindings, m_cBindings, m_hAccessor, DBACCESSOR_PARAMETERDATA);
|
|
|
|
CLEANUP :
|
|
|
|
//Clean up
|
|
if (m_hAccessor)
|
|
{
|
|
m_pIAccessor->ReleaseAccessor(m_hAccessor, NULL);
|
|
m_hAccessor = DB_NULL_HACCESSOR;
|
|
}
|
|
SAFE_RELEASE(m_pIAccessor);
|
|
FREE_BINDINGS(&m_cBindings, &m_rgBindings);
|
|
|
|
if (fSuccess)
|
|
return TEST_PASS;
|
|
else
|
|
return TEST_FAIL;
|
|
|
|
|
|
}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(8)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc One optimized, one non optimized, using same fields
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCCreateValidParamAccessors::Variation_8()
|
|
{
|
|
BOOL fSuccess = FALSE;
|
|
|
|
//Get an accessor interface on our command object
|
|
if (!VerifyInterface(m_pICommand, IID_IAccessor, COMMAND_INTERFACE,
|
|
(IUnknown **)&m_pIAccessor))
|
|
goto CLEANUP;
|
|
|
|
|
|
//Just set the command so we can do IColumnsInfo to generate accessor
|
|
if (!CHECK(m_pTable->ExecuteCommand(SELECT_VALIDATIONORDER, IID_IRowset,
|
|
NULL, NULL, NULL, NULL, EXECUTE_NEVER,
|
|
0, NULL, NULL, NULL, &m_pICommand), S_OK))
|
|
goto CLEANUP;
|
|
|
|
//Create an optmized accessor, using all the columns
|
|
if (!CHECK(GetAccessorAndBindings(m_pIAccessor,
|
|
DBACCESSOR_PARAMETERDATA | DBACCESSOR_OPTIMIZED,
|
|
&m_hAccessor, &m_rgBindings, &m_cBindings, &m_cbRowSize,
|
|
DBPART_LENGTH | DBPART_STATUS | DBPART_VALUE,
|
|
USE_COLS_TO_BIND_ARRAY, FORWARD, NO_COLS_BY_REF, NULL, NULL,
|
|
NULL, DBTYPE_EMPTY, m_cSearchableCols, m_rgSearchableCols,
|
|
g_rgParamOrds, NO_COLS_OWNED_BY_PROV, DBPARAMIO_INPUT, m_fBindLongCols),S_OK))
|
|
goto CLEANUP;
|
|
|
|
//Create a non optimized accessor using the same columns
|
|
if (!CHECK(GetAccessorAndBindings(m_pIAccessor, DBACCESSOR_PARAMETERDATA,
|
|
&m_hAccessor2, &m_rgBindings2, &m_cBindings2, &m_cbRowSize2,
|
|
DBPART_LENGTH | DBPART_STATUS | DBPART_VALUE,
|
|
USE_COLS_TO_BIND_ARRAY, FORWARD, NO_COLS_BY_REF, NULL, NULL,
|
|
NULL, DBTYPE_EMPTY, m_cSearchableCols, m_rgSearchableCols,
|
|
g_rgParamOrds, NO_COLS_OWNED_BY_PROV, DBPARAMIO_INPUT,
|
|
m_fBindLongCols),S_OK))
|
|
goto CLEANUP;
|
|
|
|
|
|
//Verify the first parameter accessor works in an execute statement
|
|
if (!CHECK(UseParamAccessorAndVerify(m_hAccessor,
|
|
DBACCESSOR_PARAMETERDATA | DBACCESSOR_OPTIMIZED,
|
|
m_cbRowSize, g_uiRowNum, m_rgBindings, m_cBindings, m_pICommand),S_OK))
|
|
goto CLEANUP;
|
|
|
|
//Verify the second parameter accessor works in an execute statement
|
|
if (!CHECK(UseParamAccessorAndVerify(m_hAccessor,
|
|
DBACCESSOR_PARAMETERDATA, m_cbRowSize2, g_uiRowNum,
|
|
m_rgBindings2, m_cBindings2, m_pICommand),S_OK))
|
|
goto CLEANUP;
|
|
|
|
//Check first accessor with GetBindings
|
|
fSuccess = VerifyBindings(m_pIAccessor, m_rgBindings, m_cBindings, m_hAccessor,
|
|
DBACCESSOR_PARAMETERDATA | DBACCESSOR_OPTIMIZED) &&
|
|
//Check second accessor with GetBindings
|
|
VerifyBindings(m_pIAccessor, m_rgBindings2, m_cBindings2, m_hAccessor2, DBACCESSOR_PARAMETERDATA);
|
|
|
|
|
|
CLEANUP:
|
|
|
|
if (m_hAccessor)
|
|
{
|
|
m_pIAccessor->ReleaseAccessor(m_hAccessor, NULL);
|
|
m_hAccessor = DB_NULL_HACCESSOR;
|
|
}
|
|
if (m_hAccessor2)
|
|
{
|
|
m_pIAccessor->ReleaseAccessor(m_hAccessor2, NULL);
|
|
m_hAccessor2 = DB_NULL_HACCESSOR;
|
|
}
|
|
SAFE_RELEASE(m_pIAccessor);
|
|
|
|
FREE_BINDINGS(&m_cBindings, &m_rgBindings);
|
|
FREE_BINDINGS(&m_cBindings2, &m_rgBindings2);
|
|
|
|
if (fSuccess)
|
|
return TEST_PASS;
|
|
else
|
|
return TEST_FAIL;
|
|
}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(9)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc One non-optimized, one optimized, using same fields - different creation sequence
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCCreateValidParamAccessors::Variation_9()
|
|
{
|
|
BOOL fSuccess = FALSE;
|
|
|
|
|
|
//Get an accessor interface on our command object
|
|
if (!VerifyInterface(m_pICommand, IID_IAccessor, COMMAND_INTERFACE,
|
|
(IUnknown **)&m_pIAccessor))
|
|
goto CLEANUP;
|
|
|
|
//Just set the command so we can do IColumnsInfo to generate accessor
|
|
if (!CHECK(m_pTable->ExecuteCommand(SELECT_VALIDATIONORDER, IID_IRowset,
|
|
NULL, NULL, NULL, NULL, EXECUTE_NEVER,
|
|
0, NULL, NULL, NULL, &m_pICommand), S_OK))
|
|
goto CLEANUP;
|
|
|
|
//Create a non optimized accessor using all the columns
|
|
if (!CHECK(GetAccessorAndBindings(m_pIAccessor, DBACCESSOR_PARAMETERDATA,
|
|
&m_hAccessor2, &m_rgBindings2, &m_cBindings2, &m_cbRowSize2,
|
|
DBPART_LENGTH | DBPART_STATUS | DBPART_VALUE,
|
|
USE_COLS_TO_BIND_ARRAY, FORWARD, NO_COLS_BY_REF, NULL, NULL,
|
|
NULL, DBTYPE_EMPTY, m_cSearchableCols, m_rgSearchableCols,
|
|
g_rgParamOrds, NO_COLS_OWNED_BY_PROV, DBPARAMIO_INPUT,
|
|
m_fBindLongCols),S_OK))
|
|
goto CLEANUP;
|
|
|
|
|
|
//Create an optmized accessor, using same columns
|
|
if (!CHECK(GetAccessorAndBindings(m_pIAccessor,
|
|
DBACCESSOR_PARAMETERDATA | DBACCESSOR_OPTIMIZED,
|
|
&m_hAccessor, &m_rgBindings, &m_cBindings, &m_cbRowSize,
|
|
DBPART_LENGTH | DBPART_STATUS | DBPART_VALUE,
|
|
USE_COLS_TO_BIND_ARRAY, FORWARD, NO_COLS_BY_REF, NULL, NULL,
|
|
NULL, DBTYPE_EMPTY, m_cSearchableCols, m_rgSearchableCols,
|
|
g_rgParamOrds, NO_COLS_OWNED_BY_PROV, DBPARAMIO_INPUT,
|
|
m_fBindLongCols),S_OK))
|
|
goto CLEANUP;
|
|
|
|
|
|
//Verify the first parameter accessor works in an execute statement
|
|
if (!CHECK(UseParamAccessorAndVerify(m_hAccessor,
|
|
DBACCESSOR_PARAMETERDATA, m_cbRowSize2, g_uiRowNum,
|
|
m_rgBindings2, m_cBindings2, m_pICommand),S_OK))
|
|
goto CLEANUP;
|
|
|
|
|
|
//Verify the second parameter accessor works in an execute statement
|
|
if (!CHECK(UseParamAccessorAndVerify(m_hAccessor,
|
|
DBACCESSOR_PARAMETERDATA | DBACCESSOR_OPTIMIZED,
|
|
m_cbRowSize, g_uiRowNum, m_rgBindings, m_cBindings, m_pICommand),S_OK))
|
|
goto CLEANUP;
|
|
|
|
|
|
//Check second accessor with GetBindings
|
|
fSuccess = VerifyBindings(m_pIAccessor, m_rgBindings, m_cBindings, m_hAccessor,
|
|
DBACCESSOR_PARAMETERDATA | DBACCESSOR_OPTIMIZED) &&
|
|
//Check first accessor with GetBindings
|
|
VerifyBindings(m_pIAccessor, m_rgBindings2, m_cBindings2, m_hAccessor2, DBACCESSOR_PARAMETERDATA);
|
|
|
|
|
|
CLEANUP:
|
|
|
|
if (m_hAccessor)
|
|
{
|
|
m_pIAccessor->ReleaseAccessor(m_hAccessor, NULL);
|
|
m_hAccessor = DB_NULL_HACCESSOR;
|
|
}
|
|
if (m_hAccessor2)
|
|
{
|
|
m_pIAccessor->ReleaseAccessor(m_hAccessor2, NULL);
|
|
m_hAccessor2 = DB_NULL_HACCESSOR;
|
|
}
|
|
SAFE_RELEASE(m_pIAccessor);
|
|
|
|
FREE_BINDINGS(&m_cBindings, &m_rgBindings);
|
|
FREE_BINDINGS(&m_cBindings2, &m_rgBindings2);
|
|
|
|
if (fSuccess)
|
|
return TEST_PASS;
|
|
else
|
|
return TEST_FAIL;
|
|
|
|
}
|
|
// }}
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(10)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc Two non-optimized, using same fields
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCCreateValidParamAccessors::Variation_10()
|
|
{
|
|
BOOL fSuccess = FALSE;
|
|
|
|
//Get an accessor interface on our command object
|
|
if (!VerifyInterface(m_pICommand, IID_IAccessor, COMMAND_INTERFACE,
|
|
(IUnknown **)&m_pIAccessor))
|
|
goto CLEANUP;
|
|
|
|
|
|
//Just set the command so we can do IColumnsInfo to generate accessor
|
|
if (!CHECK(m_pTable->ExecuteCommand(SELECT_VALIDATIONORDER, IID_IRowset,
|
|
NULL, NULL, NULL, NULL, EXECUTE_NEVER,
|
|
0, NULL, NULL, NULL, &m_pICommand), S_OK))
|
|
goto CLEANUP;
|
|
|
|
//Create an optmized accessor, using all columns
|
|
if (!CHECK(GetAccessorAndBindings(m_pIAccessor,
|
|
DBACCESSOR_PARAMETERDATA,
|
|
&m_hAccessor, &m_rgBindings, &m_cBindings, &m_cbRowSize,
|
|
DBPART_LENGTH | DBPART_STATUS | DBPART_VALUE,
|
|
USE_COLS_TO_BIND_ARRAY, FORWARD, NO_COLS_BY_REF, NULL, NULL,
|
|
NULL, DBTYPE_EMPTY, m_cSearchableCols, m_rgSearchableCols,
|
|
g_rgParamOrds, NO_COLS_OWNED_BY_PROV, DBPARAMIO_INPUT,
|
|
m_fBindLongCols),S_OK))
|
|
goto CLEANUP;
|
|
|
|
//Create another optimized accessor with same columns
|
|
if (!CHECK(GetAccessorAndBindings(m_pIAccessor,
|
|
DBACCESSOR_PARAMETERDATA,
|
|
&m_hAccessor2, &m_rgBindings2, &m_cBindings2, &m_cbRowSize2,
|
|
DBPART_LENGTH | DBPART_STATUS | DBPART_VALUE,
|
|
USE_COLS_TO_BIND_ARRAY, FORWARD, NO_COLS_BY_REF, NULL, NULL,
|
|
NULL, DBTYPE_EMPTY, m_cSearchableCols, m_rgSearchableCols,
|
|
g_rgParamOrds, NO_COLS_OWNED_BY_PROV, DBPARAMIO_INPUT,
|
|
m_fBindLongCols),S_OK))
|
|
goto CLEANUP;
|
|
|
|
|
|
//Verify the first parameter accessor works in an execute statement
|
|
if (!CHECK(UseParamAccessorAndVerify(m_hAccessor,
|
|
DBACCESSOR_PARAMETERDATA,
|
|
m_cbRowSize, g_uiRowNum, m_rgBindings, m_cBindings, m_pICommand),S_OK))
|
|
goto CLEANUP;
|
|
|
|
//Verify the second parameter accessor works in an execute statement
|
|
if (!CHECK(UseParamAccessorAndVerify(m_hAccessor,
|
|
DBACCESSOR_PARAMETERDATA,
|
|
m_cbRowSize2, g_uiRowNum, m_rgBindings2, m_cBindings2, m_pICommand),S_OK))
|
|
goto CLEANUP;
|
|
|
|
|
|
//Check first accessor with GetBindings
|
|
fSuccess = VerifyBindings(m_pIAccessor, m_rgBindings, m_cBindings, m_hAccessor,
|
|
DBACCESSOR_PARAMETERDATA) &&
|
|
//Check second accessor with GetBindings
|
|
VerifyBindings(m_pIAccessor, m_rgBindings2, m_cBindings2, m_hAccessor2, DBACCESSOR_PARAMETERDATA);
|
|
|
|
|
|
CLEANUP:
|
|
|
|
if (m_hAccessor)
|
|
{
|
|
m_pIAccessor->ReleaseAccessor(m_hAccessor, NULL);
|
|
m_hAccessor = DB_NULL_HACCESSOR;
|
|
}
|
|
if (m_hAccessor2)
|
|
{
|
|
m_pIAccessor->ReleaseAccessor(m_hAccessor2, NULL);
|
|
m_hAccessor2 = DB_NULL_HACCESSOR;
|
|
}
|
|
|
|
SAFE_RELEASE(m_pIAccessor);
|
|
FREE_BINDINGS(&m_cBindings, &m_rgBindings);
|
|
FREE_BINDINGS(&m_cBindings2, &m_rgBindings2);
|
|
|
|
if (fSuccess)
|
|
return TEST_PASS;
|
|
else
|
|
return TEST_FAIL;
|
|
|
|
|
|
}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(11)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc All searchable cols BY_REF, without DBMEMOWNER_PROVIDEROWNED
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCCreateValidParamAccessors::Variation_11()
|
|
{
|
|
BOOL fSuccess = FALSE;
|
|
|
|
// Get an accessor interface on our command object
|
|
|
|
if (!VerifyInterface(m_pICommand, IID_IAccessor, COMMAND_INTERFACE,
|
|
(IUnknown **)&m_pIAccessor))
|
|
goto CLEANUP;
|
|
|
|
|
|
//Just set the command so we can do IColumnsInfo to generate accessor
|
|
if (!CHECK(m_pTable->ExecuteCommand(SELECT_VALIDATIONORDER, IID_IRowset,
|
|
NULL, NULL, NULL, NULL, EXECUTE_NEVER,
|
|
0, NULL, NULL, NULL, &m_pICommand), S_OK))
|
|
goto CLEANUP;
|
|
|
|
//Get accessor with all searchable data type cols bound BY_REF
|
|
|
|
if (!CHECK(GetAccessorAndBindings(m_pIAccessor,
|
|
DBACCESSOR_PARAMETERDATA,
|
|
&m_hAccessor, &m_rgBindings, &m_cBindings, &m_cbRowSize,
|
|
DBPART_LENGTH | DBPART_STATUS | DBPART_VALUE,
|
|
USE_COLS_TO_BIND_ARRAY, FORWARD, ALL_COLS_BY_REF, NULL, NULL,
|
|
NULL, DBTYPE_EMPTY, m_cSearchableCols, m_rgSearchableCols, g_rgParamOrds,
|
|
NO_COLS_OWNED_BY_PROV, DBPARAMIO_INPUT,
|
|
m_fBindLongCols),S_OK))
|
|
goto CLEANUP;
|
|
|
|
//Verify the first parameter accessor works in an execute statement
|
|
|
|
// TODO Fails. RETURNS DB_E_OVERFLOW. (parameter accessor doesn't support passbyref).
|
|
if (!CHECK(UseParamAccessorAndVerify(m_hAccessor,
|
|
DBACCESSOR_PARAMETERDATA,
|
|
m_cbRowSize, g_uiRowNum, m_rgBindings, m_cBindings, m_pICommand),S_OK))
|
|
goto CLEANUP;
|
|
|
|
// Check first accessor with GetBindings
|
|
|
|
fSuccess = VerifyBindings(m_pIAccessor, m_rgBindings, m_cBindings, m_hAccessor,
|
|
DBACCESSOR_PARAMETERDATA);
|
|
|
|
CLEANUP:
|
|
|
|
if (m_pIAccessor)
|
|
{
|
|
if (m_hAccessor)
|
|
m_pIAccessor->ReleaseAccessor(m_hAccessor, NULL);
|
|
m_hAccessor = DB_NULL_HACCESSOR;
|
|
SAFE_RELEASE(m_pIAccessor);
|
|
}
|
|
|
|
FREE_BINDINGS(&m_cBindings, &m_rgBindings);
|
|
|
|
if (fSuccess)
|
|
return TEST_PASS;
|
|
else
|
|
return TEST_FAIL;
|
|
|
|
}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(12)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc More than 256 parameters
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCCreateValidParamAccessors::Variation_12()
|
|
{
|
|
|
|
BOOL fSuccess = FALSE;
|
|
DBCOUNTITEM iBinding, iCol;
|
|
HRESULT hrCreateAccessor=S_OK;
|
|
DBCOUNTITEM cAdditionalBindings=0;
|
|
WCHAR * pwszStatement=NULL;
|
|
const WCHAR wszFormat[] = L" AND %s = ?";
|
|
CCol TempCol;
|
|
WCHAR * pwszColName=NULL;
|
|
WCHAR * pwszConcatVal=NULL;
|
|
DB_LORDINAL * pParamCols=NULL;
|
|
DBROWCOUNT cRowsAffected=0;
|
|
BYTE * pData = NULL;
|
|
DBPARAMS Param;
|
|
IRowset * pRowset = NULL;
|
|
DBLENGTH ulOffset;
|
|
|
|
// Make sure there are some searchable columns
|
|
if (!m_cSearchableCols)
|
|
{
|
|
odtLog << "No searchable columns available.\n";
|
|
return TEST_SKIPPED;
|
|
}
|
|
|
|
// Retrieve the name of the first searchable column
|
|
m_pTable->GetColInfo(m_rgSearchableCols[0], TempCol);
|
|
pwszColName=TempCol.GetColName();
|
|
|
|
// Allocate some space for the column info we're going to tack on
|
|
if (!(pwszConcatVal=(WCHAR *)m_pIMalloc->Alloc((wcslen(wszFormat)+wcslen(pwszColName)+1)*sizeof(WCHAR))))
|
|
goto CLEANUP;
|
|
|
|
// Fill it
|
|
swprintf(pwszConcatVal, wszFormat, pwszColName);
|
|
|
|
//Just set the command so we can do IColumnsInfo to generate accessor
|
|
if (!CHECK(m_pTable->ExecuteCommand(SELECT_ALL_WITH_SEARCHABLE_AND_UPDATEABLE, IID_IRowset,
|
|
NULL, &pwszStatement, NULL, NULL, EXECUTE_NEVER,
|
|
0, NULL, NULL, NULL, &m_pICommand), S_OK))
|
|
goto CLEANUP;
|
|
|
|
//Get an accessor interface on our command object
|
|
if (!VerifyInterface(m_pICommand, IID_IAccessor, COMMAND_INTERFACE,
|
|
(IUnknown **)&m_pIAccessor))
|
|
goto CLEANUP;
|
|
|
|
//Create Accessor with a binding using all three parts, DBCOLUMPART_VALUE, LENGTH and STATUS.
|
|
hrCreateAccessor=GetAccessorAndBindings(m_pIAccessor, DBACCESSOR_PARAMETERDATA,
|
|
&m_hAccessor, &m_rgBindings, &m_cBindings, &m_cbRowSize,
|
|
DBPART_LENGTH | DBPART_VALUE | DBPART_STATUS, ALL_COLS_BOUND,
|
|
FORWARD, NO_COLS_BY_REF, NULL, NULL,
|
|
NULL, DBTYPE_EMPTY, 0, NULL,
|
|
NULL, NO_COLS_OWNED_BY_PROV, DBPARAMIO_INPUT,
|
|
m_fBindLongCols);
|
|
|
|
if (!CHECK(hrCreateAccessor, S_OK))
|
|
goto CLEANUP;
|
|
|
|
// Release the accessor we got previously
|
|
if (m_hAccessor)
|
|
{
|
|
m_pIAccessor->ReleaseAccessor(m_hAccessor, NULL);
|
|
m_hAccessor = DB_NULL_HACCESSOR;
|
|
}
|
|
|
|
// Compute the number of additional bindings required to hit our max
|
|
if (MAX_BIND_LIMIT > m_cBindings)
|
|
{
|
|
cAdditionalBindings=MAX_BIND_LIMIT-m_cBindings;
|
|
// Increase size of binding array
|
|
if (!(m_rgBindings=(DBBINDING *)m_pIMalloc->Realloc(m_rgBindings,
|
|
MAX_BIND_LIMIT*sizeof(DBBINDING))))
|
|
goto CLEANUP;
|
|
|
|
// Increase size of sql stmt
|
|
if (!(pwszStatement=(WCHAR *)m_pIMalloc->Realloc(pwszStatement,
|
|
(wcslen(pwszStatement)+wcslen(pwszConcatVal)*cAdditionalBindings+1)*sizeof(WCHAR))))
|
|
goto CLEANUP;
|
|
|
|
for (iBinding=m_cBindings; iBinding < m_cBindings+cAdditionalBindings; iBinding++)
|
|
{
|
|
ulOffset = ROUND_UP(sizeof(DBSTATUS), ROUND_UP_AMOUNT);
|
|
|
|
ulOffset+= sizeof(DBLENGTH)+m_rgBindings[iBinding-1].cbMaxLen;
|
|
|
|
// Adjust for alignment
|
|
ulOffset = ROUND_UP(ulOffset,ROUND_UP_AMOUNT);
|
|
|
|
memcpy(&m_rgBindings[iBinding], &m_rgBindings[0], sizeof(DBBINDING));
|
|
m_rgBindings[iBinding].iOrdinal=iBinding+1;
|
|
m_rgBindings[iBinding].obStatus=m_rgBindings[iBinding-1].obStatus+ulOffset;
|
|
m_rgBindings[iBinding].obLength=m_rgBindings[iBinding-1].obLength+ulOffset;
|
|
m_rgBindings[iBinding].obValue=m_rgBindings[iBinding-1].obValue+ulOffset;
|
|
|
|
// Increase the row size
|
|
m_cbRowSize+=ulOffset + m_rgBindings[iBinding].cbMaxLen;
|
|
|
|
wcscat(pwszStatement, pwszConcatVal);
|
|
}
|
|
m_cBindings=m_cBindings+cAdditionalBindings;
|
|
|
|
// Set the new text value
|
|
m_pTable->BuildCommand(pwszStatement, IID_IRowset, EXECUTE_NEVER, 0, NULL, NULL, NULL, NULL, &m_pICommand);
|
|
}
|
|
else
|
|
cAdditionalBindings=0;
|
|
|
|
|
|
hrCreateAccessor=m_pIAccessor->CreateAccessor(DBACCESSOR_PARAMETERDATA, m_cBindings,
|
|
m_rgBindings, m_cbRowSize, &m_hAccessor, NULL);
|
|
|
|
if (!CHECK(hrCreateAccessor, S_OK))
|
|
goto CLEANUP;
|
|
|
|
|
|
// Allocate memory for the parameter columns. This is the list of searchable
|
|
// columns from the table with the first searchable column repeated at the end
|
|
// to make up the required number of parameters.
|
|
pParamCols = (DB_LORDINAL *)m_pIMalloc->Alloc(m_cBindings*sizeof(DB_LORDINAL));
|
|
if (!pParamCols)
|
|
goto CLEANUP;
|
|
|
|
// Copy the searchable columns
|
|
memcpy(pParamCols, m_rgSearchableCols, m_cSearchableCols*sizeof(DB_LORDINAL));
|
|
|
|
// Set the rest of the columns to be the same as the first searchable one
|
|
for (iCol=m_cSearchableCols; iCol < m_cBindings; iCol++)
|
|
pParamCols[iCol]=pParamCols[0];
|
|
|
|
//GetBindings should return same values we've used to create the accessor
|
|
if (!VerifyBindings(m_pIAccessor, m_rgBindings, m_cBindings, m_hAccessor, DBACCESSOR_PARAMETERDATA))
|
|
goto CLEANUP;
|
|
|
|
//Alloc enough memory to hold a row of parameter data
|
|
pData = (BYTE *)m_pIMalloc->Alloc(m_cbRowSize);
|
|
|
|
if (!pData)
|
|
goto CLEANUP;
|
|
memset(pData, 0, (size_t)m_cbRowSize);
|
|
|
|
|
|
//Set up parameter input values for selecting row 1
|
|
if (FAILED(m_hr = FillInputBindings(m_pTable,
|
|
DBACCESSOR_PARAMETERDATA, m_cBindings, m_rgBindings, &pData, 1,
|
|
m_cBindings, pParamCols, PRIMARY)))
|
|
goto CLEANUP;
|
|
|
|
Param.cParamSets = 1;
|
|
Param.hAccessor = m_hAccessor;
|
|
Param.pData = pData;
|
|
|
|
// Now try to use the accessor
|
|
if (!CHECK(m_pICommand->Execute(NULL, IID_IRowset, &Param,
|
|
&cRowsAffected, (IUnknown **)&pRowset),S_OK))
|
|
goto CLEANUP;
|
|
|
|
/* TODO: See why this is commented out
|
|
|
|
if (!CHECK(UseParamAccessorAndVerify(m_hAccessor,
|
|
DBACCESSOR_PARAMETERDATA, m_cbRowSize, g_uiRowNum,
|
|
m_rgBindings, m_cBindings, m_pICommand),S_OK))
|
|
goto CLEANUP;
|
|
*/
|
|
|
|
odtLog << L"Created " << (ULONG)m_cBindings << L" parameters.\n";
|
|
|
|
fSuccess = TRUE;
|
|
|
|
CLEANUP :
|
|
|
|
//Clean up
|
|
SAFE_RELEASE(pRowset);
|
|
|
|
if (m_hAccessor)
|
|
{
|
|
m_pIAccessor->ReleaseAccessor(m_hAccessor, NULL);
|
|
m_hAccessor = DB_NULL_HACCESSOR;
|
|
}
|
|
SAFE_RELEASE(m_pIAccessor);
|
|
|
|
FREE_BINDINGS(&m_cBindings, &m_rgBindings);
|
|
PROVIDER_FREE(pwszStatement);
|
|
PROVIDER_FREE(pwszConcatVal);
|
|
PROVIDER_FREE(pParamCols);
|
|
PROVIDER_FREE(pData);
|
|
|
|
|
|
return (fSuccess) ? TEST_PASS : TEST_FAIL;
|
|
}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(13)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc Use DBBINDFLAGS_HTML in parameter accessor
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCCreateValidParamAccessors::Variation_13()
|
|
{
|
|
BOOL fSuccess = TEST_FAIL;
|
|
BOOL fStringType = FALSE;
|
|
ULONG iBind;
|
|
DBBINDSTATUS * pBindStatus = NULL;
|
|
|
|
// For providers that support the HTML flag, this is a success variation.
|
|
// For providers that do not support it an error should be returned. At this
|
|
// point it's not clear whether the error will occur at CreateAccessor time or
|
|
// Execute time.
|
|
|
|
//Just set the command so we can do IColumnsInfo to generate accessor
|
|
TESTC_(m_pTable->ExecuteCommand(SELECT_VALIDATIONORDER, IID_IRowset,
|
|
NULL, NULL, NULL, NULL, EXECUTE_NEVER,
|
|
0, NULL, NULL, NULL, &m_pICommand), S_OK);
|
|
|
|
//Get an accessor interface on our command object
|
|
TESTC(VerifyInterface(m_pICommand, IID_IAccessor, COMMAND_INTERFACE,
|
|
(IUnknown **)&m_pIAccessor));
|
|
|
|
//Create Accessor with a binding using all three parts, DBCOLUMPART_VALUE, LENGTH and STATUS.
|
|
TESTC_(GetAccessorAndBindings(m_pIAccessor, DBACCESSOR_PARAMETERDATA,
|
|
&m_hAccessor, &m_rgBindings, &m_cBindings, &m_cbRowSize,
|
|
DBPART_LENGTH | DBPART_VALUE | DBPART_STATUS, USE_COLS_TO_BIND_ARRAY,
|
|
FORWARD, NO_COLS_BY_REF, NULL, NULL,
|
|
NULL, DBTYPE_EMPTY, m_cSearchableCols, m_rgSearchableCols,
|
|
g_rgParamOrds, NO_COLS_OWNED_BY_PROV, DBPARAMIO_INPUT,
|
|
m_fBindLongCols),S_OK);
|
|
|
|
// Release the accessor we got above so we can change the binding information
|
|
SAFE_RELEASE_ACCESSOR(m_pIAccessor, m_hAccessor);
|
|
|
|
// Set dwFlags to DBBINDFLAG_HTML for all string types.
|
|
for(iBind = 0; iBind < m_cBindings; iBind++)
|
|
{
|
|
if (IS_BASE_TYPE(m_rgBindings[iBind].wType, DBTYPE_STR) ||
|
|
IS_BASE_TYPE(m_rgBindings[iBind].wType, DBTYPE_WSTR))
|
|
{
|
|
m_rgBindings[iBind].dwFlags = DBBINDFLAG_HTML;
|
|
fStringType = TRUE;
|
|
}
|
|
}
|
|
|
|
if (!fStringType)
|
|
{
|
|
odtLog << L"No string types available to test.\n";
|
|
fSuccess = TEST_SKIPPED;
|
|
goto CLEANUP;
|
|
}
|
|
|
|
// Now recreate the accessor. Note specifying DBBINDFLAGS_HTML is legal even if provider
|
|
// doesn't support it. It should be ignored.
|
|
TESTC_(m_pIAccessor->CreateAccessor(DBACCESSOR_PARAMETERDATA, m_cBindings, m_rgBindings, m_cbRowSize,
|
|
&m_hAccessor, pBindStatus), S_OK);
|
|
|
|
// Verify. The expected result is a failure for providers that don't support the HTML flag.
|
|
// Per spec, providers that don't support the HTML flag can't use the flag to set data.
|
|
UseParamAccessorAndVerify(m_hAccessor, DBACCESSOR_PARAMETERDATA, m_cbRowSize, g_uiRowNum,
|
|
m_rgBindings, m_cBindings, m_pICommand, DB_E_BADBINDINFO, TRUE);
|
|
|
|
//GetBindings should return same values we've used to create the accessor
|
|
TESTC(VerifyBindings(m_pIAccessor, m_rgBindings, m_cBindings, m_hAccessor, DBACCESSOR_PARAMETERDATA));
|
|
|
|
fSuccess = TEST_PASS;
|
|
|
|
CLEANUP :
|
|
|
|
//Clean up
|
|
SAFE_RELEASE_ACCESSOR(m_pIAccessor, m_hAccessor);
|
|
SAFE_RELEASE(m_pIAccessor);
|
|
FREE_BINDINGS(&m_cBindings, &m_rgBindings);
|
|
|
|
return fSuccess;
|
|
|
|
}
|
|
// }} TCW_VAR_PROTOTYPE_END
|
|
|
|
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(14)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc DBACCESSOR_INHERITED - Or'd with DBACCESSOR_OPTIMIZED
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCCreateValidParamAccessors::Variation_14()
|
|
{
|
|
HACCESSOR hAccInherited = m_hAccessor;
|
|
HACCESSOR hAccInherited2 = m_hAccessor2;
|
|
DBBINDSTATUS * pBindStatus;
|
|
DBBINDSTATUS * pBindStatus2;
|
|
BOOL fSuccess = FALSE;
|
|
HRESULT hr = E_FAIL;
|
|
|
|
//Get an accessor interface on our command object
|
|
if (!VerifyInterface(m_pICommand, IID_IAccessor, COMMAND_INTERFACE,
|
|
(IUnknown **)&m_pIAccessor))
|
|
goto CLEANUP;
|
|
|
|
//Just set the command so we can do IColumnsInfo to generate accessor
|
|
TESTC_(m_pTable->ExecuteCommand(SELECT_VALIDATIONORDER, IID_IRowset,
|
|
NULL, NULL, NULL, NULL, EXECUTE_NEVER,
|
|
0, NULL, NULL, NULL, &m_pICommand), S_OK);
|
|
|
|
//Create an optmized accessor, using all the columns
|
|
TESTC_(GetAccessorAndBindings(m_pIAccessor,
|
|
DBACCESSOR_PARAMETERDATA | DBACCESSOR_OPTIMIZED,
|
|
&m_hAccessor, &m_rgBindings, &m_cBindings, &m_cbRowSize,
|
|
DBPART_LENGTH | DBPART_STATUS | DBPART_VALUE,
|
|
USE_COLS_TO_BIND_ARRAY, FORWARD, NO_COLS_BY_REF, NULL, NULL,
|
|
NULL, DBTYPE_EMPTY, m_cSearchableCols, m_rgSearchableCols,
|
|
g_rgParamOrds, NO_COLS_OWNED_BY_PROV, DBPARAMIO_INPUT, m_fBindLongCols),S_OK);
|
|
|
|
//Create a non optimized accessor using the same columns
|
|
TESTC_(GetAccessorAndBindings(m_pIAccessor, DBACCESSOR_PARAMETERDATA,
|
|
&m_hAccessor2, &m_rgBindings2, &m_cBindings2, &m_cbRowSize2,
|
|
DBPART_LENGTH | DBPART_STATUS | DBPART_VALUE,
|
|
USE_COLS_TO_BIND_ARRAY, FORWARD, NO_COLS_BY_REF, NULL, NULL,
|
|
NULL, DBTYPE_EMPTY, m_cSearchableCols, m_rgSearchableCols,
|
|
g_rgParamOrds, NO_COLS_OWNED_BY_PROV, DBPARAMIO_INPUT,
|
|
m_fBindLongCols),S_OK);
|
|
|
|
// Specify the input arguments - the original accessor handles
|
|
hAccInherited = m_hAccessor;
|
|
hAccInherited2 = m_hAccessor2;
|
|
|
|
// Allocate memory for DBBINDSTATUS arrays
|
|
SAFE_ALLOC(pBindStatus, DBSTATUS, m_cBindings);
|
|
SAFE_ALLOC(pBindStatus2, DBSTATUS, m_cBindings2);
|
|
|
|
// Now create new accessors specifying DBACCESSOR_INHERITED flag. Note that phAccessor
|
|
// is an input argument. Since the INHERITED flag is *only* for row accessors this should be
|
|
// DB_E_BADACCESSORFLAGS.
|
|
TESTC_(m_pIAccessor->CreateAccessor (
|
|
DBACCESSOR_PARAMETERDATA | DBACCESSOR_INHERITED,
|
|
m_cBindings2, m_rgBindings2, m_cbRowSize2, &hAccInherited2, pBindStatus2),
|
|
DB_E_BADACCESSORFLAGS);
|
|
|
|
// Try with OPTIMIZED flag also.
|
|
TESTC_(m_pIAccessor->CreateAccessor (
|
|
DBACCESSOR_ROWDATA | DBACCESSOR_OPTIMIZED | DBACCESSOR_INHERITED,
|
|
m_cBindings, m_rgBindings, m_cbRowSize, &hAccInherited, pBindStatus),
|
|
DB_E_BADACCESSORFLAGS);
|
|
|
|
// Make sure the original accessors still work
|
|
|
|
//Verify the first parameter accessor works in an execute statement
|
|
if (!CHECK(UseParamAccessorAndVerify(m_hAccessor,
|
|
DBACCESSOR_PARAMETERDATA | DBACCESSOR_OPTIMIZED,
|
|
m_cbRowSize, g_uiRowNum, m_rgBindings, m_cBindings, m_pICommand),S_OK))
|
|
goto CLEANUP;
|
|
|
|
//Verify the second parameter accessor works in an execute statement
|
|
if (!CHECK(UseParamAccessorAndVerify(m_hAccessor,
|
|
DBACCESSOR_PARAMETERDATA, m_cbRowSize2, g_uiRowNum,
|
|
m_rgBindings2, m_cBindings2, m_pICommand),S_OK))
|
|
goto CLEANUP;
|
|
|
|
//Check first accessor with GetBindings
|
|
fSuccess = VerifyBindings(m_pIAccessor, m_rgBindings, m_cBindings, m_hAccessor,
|
|
DBACCESSOR_PARAMETERDATA | DBACCESSOR_OPTIMIZED) &&
|
|
//Check second accessor with GetBindings
|
|
VerifyBindings(m_pIAccessor, m_rgBindings2, m_cBindings2, m_hAccessor2, DBACCESSOR_PARAMETERDATA);
|
|
|
|
|
|
CLEANUP:
|
|
|
|
SAFE_RELEASE_ACCESSOR(m_pIAccessor, hAccInherited);
|
|
SAFE_RELEASE_ACCESSOR(m_pIAccessor, hAccInherited2);
|
|
SAFE_RELEASE_ACCESSOR(m_pIAccessor, m_hAccessor);
|
|
SAFE_RELEASE_ACCESSOR(m_pIAccessor, m_hAccessor2);
|
|
SAFE_RELEASE(m_pIAccessor);
|
|
|
|
FREE_BINDINGS(&m_cBindings, &m_rgBindings);
|
|
FREE_BINDINGS(&m_cBindings2, &m_rgBindings2);
|
|
|
|
SAFE_FREE(pBindStatus);
|
|
SAFE_FREE(pBindStatus2);
|
|
|
|
if (fSuccess)
|
|
return TEST_PASS;
|
|
else
|
|
return TEST_FAIL;
|
|
}
|
|
// }} TCW_VAR_PROTOTYPE_END
|
|
|
|
|
|
// {{ TCW_TERMINATE_METHOD
|
|
//--------------------------------------------------------------------
|
|
// @mfunc TestCase Termination Routine
|
|
//
|
|
// @rdesc TRUE or FALSE
|
|
//
|
|
BOOL TCCreateValidParamAccessors::Terminate()
|
|
{
|
|
|
|
if (m_pTable)
|
|
{
|
|
m_pTable->DropTable();
|
|
delete m_pTable;
|
|
}
|
|
|
|
//Set our table back to the default one for the whole test module
|
|
m_pTable = m_pSaveTable;
|
|
|
|
PROVIDER_FREE(m_rgSearchableCols);
|
|
|
|
// {{ TCW_TERM_BASECLASS_CHECK2
|
|
return(CAccessor::Terminate());
|
|
} // }}
|
|
// }}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_TC_PROTOTYPE(TCAccessorSequencing)
|
|
//*-----------------------------------------------------------------------
|
|
//| Test Case: TCAccessorSequencing - Accessors created and used in various sequences
|
|
//| Created: 11/11/95
|
|
//*-----------------------------------------------------------------------
|
|
|
|
//--------------------------------------------------------------------
|
|
// @mfunc TestCase Initialization Routine
|
|
//
|
|
// @rdesc TRUE or FALSE
|
|
//
|
|
BOOL TCAccessorSequencing::Init()
|
|
{
|
|
|
|
// {{ TCW_INIT_BASECLASS_CHECK
|
|
if(CAccessor::Init())
|
|
// }}
|
|
{
|
|
TESTC_(OpenRowsetObject(FALSE), S_OK);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
CLEANUP:
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(1)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc One accessor created on command, one on rowset
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCAccessorSequencing::Variation_1()
|
|
{
|
|
BOOL fSuccess = FALSE;
|
|
ICommand * pICommand = NULL;
|
|
|
|
if (!g_fCmdSupported)
|
|
{
|
|
//provider does not support commands
|
|
odtLog << wszCommandNotSupported;
|
|
return TEST_SKIPPED;
|
|
}
|
|
|
|
|
|
//Create an accessor on the command object
|
|
if (!CHECK(m_pCmdIAccessor->CreateAccessor(DBACCESSOR_ROWDATA, m_cBindings, m_rgBindings,
|
|
m_cbRowSize, &m_hAccessor2, NULL), S_OK))
|
|
goto CLEANUP;
|
|
|
|
TESTC_(OpenRowsetObject(FALSE), S_OK);
|
|
|
|
//Create an accessor on the rowset object
|
|
if (!CHECK(m_pIAccessor->CreateAccessor(DBACCESSOR_ROWDATA, m_cBindings, m_rgBindings,
|
|
m_cbRowSize, &m_hAccessor, NULL), S_OK))
|
|
goto CLEANUP;
|
|
|
|
//Make sure we can GetBindings at this point
|
|
if (!VerifyBindings(m_pCmdIAccessor, m_rgBindings, m_cBindings, m_hAccessor2,
|
|
DBACCESSOR_ROWDATA))
|
|
goto CLEANUP;
|
|
|
|
|
|
//Now use both accessors on rowset
|
|
|
|
//Try rowset created accessor first
|
|
if (!CHECK(UseRowAccessorAndVerify(m_hAccessor, m_cbRowSize, g_uiRowNum,
|
|
m_rgTableColOrds, m_cBindings, m_rgBindings, m_cBindings,
|
|
FALSE, TRUE),S_OK)) //Keep same rows to be gotten by next call
|
|
goto CLEANUP;
|
|
|
|
if(g_fCmdSupported)
|
|
{
|
|
//Next try command created accessor
|
|
if (!CHECK(UseRowAccessorAndVerify(m_hAccessor2, m_cbRowSize, g_uiRowNum,
|
|
m_rgTableColOrds, m_cBindings, m_rgBindings, m_cBindings,
|
|
FALSE, TRUE),S_OK))
|
|
goto CLEANUP;
|
|
}
|
|
|
|
//Check bindings on command before we release inherited accessor on the command
|
|
if (!VerifyBindings(m_pCmdIAccessor, m_rgBindings, m_cBindings, m_hAccessor2,
|
|
DBACCESSOR_ROWDATA))
|
|
goto CLEANUP;
|
|
|
|
//Should be able to release inherited accessor on the command without
|
|
//any effect on the rowset. Note we don't null the handle 'cause we want to
|
|
// use it again.
|
|
if (m_hAccessor2)
|
|
{
|
|
CHECK(m_pCmdIAccessor->ReleaseAccessor(m_hAccessor2, NULL),S_OK);
|
|
}
|
|
|
|
if(g_fCmdSupported)
|
|
{
|
|
//Using inherited command accessor on rowset after it's been released on
|
|
//the command should work
|
|
if (!CHECK(UseRowAccessorAndVerify(m_hAccessor2, m_cbRowSize, g_uiRowNum,
|
|
m_rgTableColOrds, m_cBindings, m_rgBindings, m_cBindings),S_OK))
|
|
goto CLEANUP;
|
|
}
|
|
|
|
//Check accessors with GetBindings done on rowset's IAccessor interface
|
|
if (!VerifyBindings(m_pIAccessor, m_rgBindings, m_cBindings, m_hAccessor,
|
|
DBACCESSOR_ROWDATA))
|
|
goto CLEANUP;
|
|
if (!VerifyBindings(m_pIAccessor, m_rgBindings, m_cBindings, m_hAccessor2,
|
|
DBACCESSOR_ROWDATA))
|
|
goto CLEANUP;
|
|
|
|
|
|
fSuccess = TRUE;
|
|
|
|
CLEANUP:
|
|
|
|
//We have to clean up since we kept the row in UseRowAccessorAndVerify
|
|
if(m_hRow && m_fIRowset)
|
|
{
|
|
m_pIRowset->ReleaseRows(m_cRowsObtained,&m_hRow,NULL, NULL,NULL);
|
|
m_hRow = DB_NULL_HROW;
|
|
}
|
|
|
|
|
|
//Make it clear to other variations that hRow is invalid
|
|
m_hRow = DB_NULL_HROW;
|
|
|
|
SAFE_RELEASE_ACCESSOR(m_pIAccessor, m_hAccessor);
|
|
|
|
CleanUpRowsetObject();
|
|
|
|
return (fSuccess) ? TEST_PASS : TEST_FAIL;
|
|
|
|
}
|
|
|
|
// }}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(2)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc One accessor created on command, one on rowset, using different fields
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCAccessorSequencing::Variation_2()
|
|
{
|
|
BOOL fSuccess = FALSE;
|
|
DBORDINAL cCols;
|
|
|
|
if (!g_fCmdSupported)
|
|
{
|
|
//provider does not support commands
|
|
odtLog << wszCommandNotSupported;
|
|
return TEST_SKIPPED;
|
|
}
|
|
|
|
TESTC_(OpenRowsetObject(FALSE), S_OK);
|
|
|
|
//Create an accessor on the command object, using
|
|
//binding info generated in init, which binds all cols
|
|
if (!CHECK(m_pCmdIAccessor->CreateAccessor(DBACCESSOR_ROWDATA, m_cBindings, m_rgBindings,
|
|
m_cbRowSize, &m_hAccessor, NULL), S_OK))
|
|
goto CLEANUP;
|
|
|
|
TESTC_(OpenRowsetObject(FALSE), S_OK);
|
|
|
|
//Create an accessor on the rowset object, using only odd cols
|
|
if (!CHECK(GetAccessorAndBindings(m_pIAccessor,
|
|
DBACCESSOR_ROWDATA, &m_hAccessor2, &m_rgBindings2,
|
|
&m_cBindings2, &m_cbRowSize2, DBPART_VALUE |
|
|
DBPART_STATUS | DBPART_LENGTH, ODD_COLS_BOUND,
|
|
FORWARD, NO_COLS_BY_REF, NULL, &cCols,
|
|
NULL, DBTYPE_EMPTY, 0, NULL, NULL,
|
|
NO_COLS_OWNED_BY_PROV, DBPARAMIO_NOTPARAM,
|
|
m_fBindLongCols),S_OK))
|
|
goto CLEANUP;
|
|
|
|
//Now use both accessors on rowset
|
|
|
|
//Try rowset created accessor first
|
|
if (!CHECK(UseRowAccessorAndVerify(m_hAccessor2, m_cbRowSize2, g_uiRowNum,
|
|
m_rgTableColOrds, cCols, m_rgBindings2, m_cBindings2,
|
|
FALSE, TRUE),S_OK))
|
|
goto CLEANUP;
|
|
|
|
//Next try command created accessor
|
|
if (!CHECK(UseRowAccessorAndVerify(m_hAccessor, m_cbRowSize, g_uiRowNum,
|
|
m_rgTableColOrds, m_cBindings, m_rgBindings, m_cBindings),S_OK))
|
|
goto CLEANUP;
|
|
|
|
//Check accessors with GetBindings done on rowset's IAccessor interface
|
|
if (!VerifyBindings(m_pIAccessor, m_rgBindings, m_cBindings, m_hAccessor,
|
|
DBACCESSOR_ROWDATA))
|
|
goto CLEANUP;
|
|
|
|
if (!VerifyBindings(m_pIAccessor, m_rgBindings2, m_cBindings2, m_hAccessor2,
|
|
DBACCESSOR_ROWDATA))
|
|
goto CLEANUP;
|
|
|
|
//Now check command accessor with GetBindings done on command's IAccessor interface
|
|
if (!VerifyBindings(m_pCmdIAccessor, m_rgBindings, m_cBindings, m_hAccessor,
|
|
DBACCESSOR_ROWDATA))
|
|
goto CLEANUP;
|
|
|
|
fSuccess = TRUE;
|
|
|
|
CLEANUP:
|
|
|
|
if (m_hAccessor2 && m_pIAccessor)
|
|
{
|
|
CHECK(m_pIAccessor->ReleaseAccessor(m_hAccessor2, NULL),S_OK);
|
|
m_hAccessor2 = DB_NULL_HACCESSOR;
|
|
}
|
|
PROVIDER_FREE(m_rgBindings2);
|
|
|
|
//We have to clean up since we kept the row in UseRowAccessorAndVerify
|
|
if(m_hRow && m_pIRowset)
|
|
{
|
|
m_pIRowset->ReleaseRows(m_cRowsObtained,&m_hRow, NULL, NULL,NULL);
|
|
m_hRow = DB_NULL_HROW;
|
|
}
|
|
|
|
|
|
//Make it clear to other variations that hRow is invalid
|
|
m_hRow = DB_NULL_HROW;
|
|
|
|
CleanUpRowsetObject();
|
|
|
|
return (fSuccess) ? TEST_PASS : TEST_FAIL;
|
|
|
|
}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(3)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc Two ROWDATA accessors on command object, one before and one after execute
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCAccessorSequencing::Variation_3()
|
|
{
|
|
HROW * rgOnehRow = &m_hRow;
|
|
BOOL fSuccess = FALSE;
|
|
BYTE * pData = (BYTE *)1; //We should error out before this gets touched,
|
|
//so use a bogus value for it
|
|
|
|
if (!g_fCmdSupported)
|
|
{
|
|
//provider does not support commands
|
|
odtLog << wszCommandNotSupported;
|
|
return TEST_SKIPPED;
|
|
}
|
|
|
|
TESTC_(OpenRowsetObject(FALSE), S_OK);
|
|
|
|
//Create an accessor on the command object, using
|
|
//binding info generated in init, which binds all cols.
|
|
//This way we get coverage before a command is set
|
|
if (!CHECK(m_pCmdIAccessor->CreateAccessor(DBACCESSOR_ROWDATA, m_cBindings, m_rgBindings,
|
|
m_cbRowSize, &m_hAccessor, NULL), S_OK))
|
|
goto CLEANUP;
|
|
|
|
TESTC_(OpenRowsetObject(FALSE), S_OK);
|
|
|
|
//Create another accessor on the command object, after execute
|
|
if (!CHECK(m_pCmdIAccessor->CreateAccessor(DBACCESSOR_ROWDATA, m_cBindings, m_rgBindings,
|
|
m_cbRowSize, &m_hAccessor2, NULL), S_OK))
|
|
goto CLEANUP;
|
|
|
|
//Make sure we can do GetBindings at this point
|
|
if (!VerifyBindings(m_pCmdIAccessor, m_rgBindings, m_cBindings, m_hAccessor,
|
|
DBACCESSOR_ROWDATA))
|
|
goto CLEANUP;
|
|
if (!VerifyBindings(m_pCmdIAccessor, m_rgBindings, m_cBindings, m_hAccessor2,
|
|
DBACCESSOR_ROWDATA))
|
|
goto CLEANUP;
|
|
|
|
|
|
if(g_fCmdSupported)
|
|
{
|
|
//Try command accessor created before execute - should work
|
|
if (!CHECK(UseRowAccessorAndVerify(m_hAccessor, m_cbRowSize, g_uiRowNum,
|
|
m_rgTableColOrds, m_cBindings, m_rgBindings, m_cBindings),S_OK))
|
|
goto CLEANUP;
|
|
}
|
|
|
|
//Try accessor created after execute - should fail because it was created after
|
|
//the rowset was
|
|
if (m_fIRowset)
|
|
{
|
|
// This could return DB_S_COMMANDREEXECUTED as well as S_OK.
|
|
if (!SUCCEEDED(m_pIRowset->RestartPosition(NULL)))
|
|
goto CLEANUP;
|
|
|
|
if (CHECK(m_hr = m_pIRowset->GetNextRows(NULL, 0, 1,
|
|
&m_cRowsObtained, (HROW **)&rgOnehRow), S_OK))
|
|
{
|
|
if (!CHECK(m_pIRowset->GetData(m_hRow, m_hAccessor2, pData), DB_E_BADACCESSORHANDLE))
|
|
{
|
|
CHECK(m_pIRowset->ReleaseRows(1,rgOnehRow, NULL, NULL, NULL), S_OK);
|
|
m_hRow = DB_NULL_HROW;
|
|
goto CLEANUP;
|
|
}
|
|
|
|
CHECK(m_pIRowset->ReleaseRows(1,rgOnehRow, NULL, NULL, NULL), S_OK);
|
|
m_hRow = DB_NULL_HROW;
|
|
if(pData!=(BYTE *)1)
|
|
goto CLEANUP;
|
|
}
|
|
else
|
|
goto CLEANUP;
|
|
}
|
|
else
|
|
goto CLEANUP;
|
|
|
|
//Check accessor with GetBindings done on rowset's IAccessor interface
|
|
if (!VerifyBindings(m_pIAccessor, m_rgBindings, m_cBindings, m_hAccessor,
|
|
DBACCESSOR_ROWDATA))
|
|
goto CLEANUP;
|
|
|
|
//Now check both command accessors with GetBindings done on command's IAccessor interface
|
|
if (!VerifyBindings(m_pCmdIAccessor, m_rgBindings, m_cBindings, m_hAccessor2,
|
|
DBACCESSOR_ROWDATA) ||
|
|
!VerifyBindings(m_pCmdIAccessor, m_rgBindings, m_cBindings, m_hAccessor,
|
|
DBACCESSOR_ROWDATA))
|
|
goto CLEANUP;
|
|
|
|
fSuccess = TRUE;
|
|
|
|
CLEANUP:
|
|
|
|
CleanUpRowsetObject();
|
|
|
|
return (fSuccess) ? TEST_PASS : TEST_FAIL;
|
|
}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(4)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc Create and use accessor after Setting command
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCAccessorSequencing::Variation_4()
|
|
{
|
|
BOOL fSuccess = FALSE;
|
|
DBORDINAL cCols;
|
|
|
|
if (!g_fCmdSupported)
|
|
{
|
|
//provider does not support commands
|
|
odtLog << wszCommandNotSupported;
|
|
return TEST_SKIPPED;
|
|
}
|
|
|
|
TESTC_(OpenRowsetObject(FALSE), S_OK);
|
|
|
|
// Release the rowset but leave the command object
|
|
SAFE_RELEASE(m_pIRowset);
|
|
SAFE_RELEASE(m_pIAccessor);
|
|
SAFE_FREE(m_rgTableColOrds);
|
|
FREE_BINDINGS(&m_cBindings, &m_rgBindings);
|
|
|
|
//Set command, but don't execute
|
|
if (!CHECK(m_pTable->ExecuteCommand(SELECT_VALIDATIONORDER,
|
|
IID_IRowset, NULL, NULL, &cCols, &m_rgTableColOrds, EXECUTE_NEVER,
|
|
0, NULL, NULL, NULL, &m_pICommand), S_OK))
|
|
goto CLEANUP;
|
|
|
|
//Create an accessor on the command object
|
|
if (!CHECK(GetAccessorAndBindings(m_pCmdIAccessor,
|
|
DBACCESSOR_ROWDATA, &m_hAccessor, &m_rgBindings,
|
|
&m_cBindings, &m_cbRowSize, DBPART_VALUE |
|
|
DBPART_STATUS | DBPART_LENGTH, EVEN_COLS_BOUND,
|
|
FORWARD, NO_COLS_BY_REF, NULL, &cCols,
|
|
NULL, DBTYPE_EMPTY, 0, NULL, NULL,
|
|
NO_COLS_OWNED_BY_PROV, DBPARAMIO_NOTPARAM,
|
|
m_fBindLongCols),S_OK))
|
|
goto CLEANUP;
|
|
|
|
//Make sure we can do GetBindings at this point
|
|
if (!VerifyBindings(m_pCmdIAccessor, m_rgBindings, m_cBindings, m_hAccessor,
|
|
DBACCESSOR_ROWDATA))
|
|
goto CLEANUP;
|
|
|
|
//Execute command
|
|
if (!CHECK(m_pICommand->Execute(NULL, IID_IAccessor, NULL,
|
|
NULL, (IUnknown **)&m_pIAccessor),S_OK))
|
|
goto CLEANUP;
|
|
|
|
//Try to get an IRowset interface
|
|
if(VerifyInterface(m_pIAccessor,IID_IRowset,ROWSET_INTERFACE,
|
|
(IUnknown **)&m_pIRowset))
|
|
{
|
|
//Record that IRowset is supported
|
|
m_fIRowset = TRUE;
|
|
}
|
|
|
|
if(g_fCmdSupported)
|
|
{
|
|
//Now use accessor
|
|
if (!CHECK(UseRowAccessorAndVerify(m_hAccessor, m_cbRowSize, g_uiRowNum,
|
|
m_rgTableColOrds, cCols, m_rgBindings, m_cBindings),S_OK))
|
|
goto CLEANUP;
|
|
}
|
|
|
|
//Check accessors with GetBindings on rowset's IAccessor
|
|
if (VerifyBindings(m_pIAccessor, m_rgBindings, m_cBindings, m_hAccessor,
|
|
DBACCESSOR_ROWDATA))
|
|
{
|
|
//Now verify bindings using command's IAccessor
|
|
fSuccess = VerifyBindings(m_pCmdIAccessor, m_rgBindings, m_cBindings, m_hAccessor,
|
|
DBACCESSOR_ROWDATA);
|
|
}
|
|
|
|
|
|
CLEANUP:
|
|
|
|
//Release the interface we allocated on rowset object
|
|
SAFE_RELEASE(m_pIRowset);
|
|
SAFE_RELEASE(m_pIAccessor);
|
|
|
|
if (m_hAccessor)
|
|
{
|
|
CHECK(m_pCmdIAccessor->ReleaseAccessor(m_hAccessor, NULL),S_OK);
|
|
m_hAccessor = DB_NULL_HACCESSOR;
|
|
}
|
|
|
|
return (fSuccess) ? TEST_PASS : TEST_FAIL;
|
|
}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(5)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc Create and use accessor after reading data via IRowset
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCAccessorSequencing::Variation_5()
|
|
{
|
|
BOOL fSuccess = FALSE;
|
|
HROW * rghRow = &m_hRow;
|
|
BYTE * pData = NULL;
|
|
DBCOUNTITEM cRows = 1;
|
|
DBROWCOUNT cRowSkip;
|
|
|
|
if (!g_fCmdSupported)
|
|
{
|
|
//provider does not support commands
|
|
odtLog << wszCommandNotSupported;
|
|
return TEST_SKIPPED;
|
|
}
|
|
|
|
TESTC_(OpenRowsetObject(FALSE), S_OK);
|
|
|
|
// Skip any existing rows in the table and get the last one.
|
|
cRowSkip = m_pTable->GetRowsOnCTable()-1;
|
|
|
|
//Get a row before creating the accessors
|
|
m_hRow = DB_NULL_HROW;
|
|
|
|
if (!CHECK(m_pIRowset->GetNextRows(NULL,cRowSkip, 1,
|
|
&cRows, &rghRow),S_OK))
|
|
goto CLEANUP;
|
|
|
|
//Create an accessor on the command object using bindings we got earlier
|
|
if (!CHECK(m_pCmdIAccessor->CreateAccessor(DBACCESSOR_ROWDATA,
|
|
m_cBindings, m_rgBindings, m_cbRowSize, &m_hAccessor, NULL), S_OK))
|
|
goto CLEANUP;
|
|
|
|
//Create an accessor on the rowset object
|
|
if (!CHECK(GetAccessorAndBindings(m_pIAccessor,
|
|
DBACCESSOR_ROWDATA, &m_hAccessor2, &m_rgBindings2,
|
|
&m_cBindings2, &m_cbRowSize2, DBPART_VALUE |
|
|
DBPART_STATUS | DBPART_LENGTH, ALL_COLS_BOUND,
|
|
FORWARD, NO_COLS_BY_REF, NULL, NULL,
|
|
NULL, DBTYPE_EMPTY, 0, NULL, NULL,
|
|
NO_COLS_OWNED_BY_PROV, DBPARAMIO_NOTPARAM,
|
|
m_fBindLongCols),S_OK))
|
|
goto CLEANUP;
|
|
|
|
pData = (BYTE *)m_pIMalloc->Alloc(m_cbRowSize2);
|
|
if (!pData)
|
|
goto CLEANUP;
|
|
|
|
//Use rowset accessor
|
|
if (!CHECK(m_pIRowset->GetData(m_hRow, m_hAccessor2, pData), S_OK))
|
|
goto CLEANUP;
|
|
|
|
//Verify data value, length and status are what is expected
|
|
TESTC(CompareData(m_cBindings, m_rgTableColOrds, g_uiRowNum+cRowSkip, pData, m_cBindings2,
|
|
m_rgBindings2, m_pTable, m_pIMalloc));
|
|
|
|
//Check accessor with GetBindings on rowset's IAccessor
|
|
if (!VerifyBindings(m_pIAccessor, m_rgBindings2, m_cBindings2, m_hAccessor2,
|
|
DBACCESSOR_ROWDATA))
|
|
goto CLEANUP;
|
|
|
|
|
|
//Now check command accessor on the command's IAccessor
|
|
if (!VerifyBindings(m_pCmdIAccessor, m_rgBindings, m_cBindings, m_hAccessor,
|
|
DBACCESSOR_ROWDATA))
|
|
goto CLEANUP;
|
|
|
|
//Everything went OK if we got this far
|
|
fSuccess = TRUE;
|
|
|
|
CLEANUP:
|
|
|
|
SAFE_RELEASE_ACCESSOR(m_pCmdIAccessor, m_hAccessor);
|
|
SAFE_RELEASE_ACCESSOR(m_pIAccessor, m_hAccessor2);
|
|
|
|
PROVIDER_FREE(pData);
|
|
|
|
if (m_hRow && m_pIRowset)
|
|
{
|
|
m_pIRowset->ReleaseRows(1, &m_hRow, NULL, NULL, NULL);
|
|
m_hRow = DB_NULL_HROW;
|
|
}
|
|
|
|
FREE_BINDINGS(&m_cBindings2, &m_rgBindings2);
|
|
CleanUpRowsetObject();
|
|
|
|
return (fSuccess) ? TEST_PASS : TEST_FAIL;
|
|
|
|
}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(6)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc Create and use accessor after GetData
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCAccessorSequencing::Variation_6()
|
|
{
|
|
BOOL fSuccess = FALSE;
|
|
HROW * rghRow = &m_hRow;
|
|
BYTE * pData = NULL;
|
|
DBCOUNTITEM cRows = 1;
|
|
DBCOUNTITEM cRowSkip;
|
|
|
|
if (!g_fCmdSupported)
|
|
{
|
|
//provider does not support commands
|
|
odtLog << wszCommandNotSupported;
|
|
return TEST_SKIPPED;
|
|
}
|
|
|
|
// We don't want our default rowset object from init
|
|
CleanUpRowsetObject();
|
|
|
|
// Skip any existing rows in the table and get the last one.
|
|
cRowSkip = m_pTable->GetRowsOnCTable()-1;
|
|
|
|
//Set command, but don't execute
|
|
if (!CHECK(m_pTable->ExecuteCommand(SELECT_VALIDATIONORDER,
|
|
IID_IRowset, NULL, NULL, NULL, NULL, EXECUTE_NEVER,
|
|
0, NULL, NULL, NULL, &m_pICommand), S_OK))
|
|
goto CLEANUP;
|
|
|
|
TESTC_(OpenRowsetObject(FALSE), S_OK);
|
|
|
|
m_hRow = DB_NULL_HROW;
|
|
|
|
//Get a row before creating the accessor
|
|
if (!CHECK(m_pIRowset->GetNextRows(NULL, cRowSkip, 1,
|
|
&cRows, &rghRow),S_OK))
|
|
goto CLEANUP;
|
|
|
|
//Create an accessor on the command object
|
|
if (!CHECK(m_pCmdIAccessor->CreateAccessor(DBACCESSOR_ROWDATA,m_cBindings,
|
|
m_rgBindings, m_cbRowSize, &m_hAccessor, NULL), S_OK))
|
|
goto CLEANUP;
|
|
|
|
//Create an accessor on the rowset object
|
|
if (!CHECK(GetAccessorAndBindings(m_pIAccessor,
|
|
DBACCESSOR_ROWDATA, &m_hAccessor2, &m_rgBindings2,
|
|
&m_cBindings2, &m_cbRowSize2, DBPART_VALUE |
|
|
DBPART_STATUS | DBPART_LENGTH, ALL_COLS_BOUND,
|
|
FORWARD, NO_COLS_BY_REF, NULL, NULL,
|
|
NULL, DBTYPE_EMPTY, 0, NULL, NULL,
|
|
NO_COLS_OWNED_BY_PROV, DBPARAMIO_NOTPARAM,
|
|
m_fBindLongCols),S_OK))
|
|
goto CLEANUP;
|
|
|
|
pData = (BYTE *)m_pIMalloc->Alloc(m_cbRowSize2);
|
|
if (!pData)
|
|
goto CLEANUP;
|
|
|
|
//Now use rowset accessor
|
|
if (!CHECK(m_pIRowset->GetData(m_hRow, m_hAccessor2, pData), S_OK))
|
|
goto CLEANUP;
|
|
|
|
//Verify data value, length and status are what is expected
|
|
if (!CompareData(m_cBindings2, m_rgTableColOrds, g_uiRowNum+cRowSkip,pData, m_cBindings2,
|
|
m_rgBindings2, m_pTable, m_pIMalloc))
|
|
goto CLEANUP;
|
|
|
|
//Check accessors with GetBindings on rowset's IAccessor
|
|
if (!VerifyBindings(m_pIAccessor, m_rgBindings2, m_cBindings2, m_hAccessor2,
|
|
DBACCESSOR_ROWDATA))
|
|
goto CLEANUP;
|
|
|
|
//Check accessors with GetBindings on command's IAccessor
|
|
if (!VerifyBindings(m_pCmdIAccessor, m_rgBindings, m_cBindings, m_hAccessor,
|
|
DBACCESSOR_ROWDATA))
|
|
goto CLEANUP;
|
|
|
|
|
|
fSuccess = TRUE;
|
|
|
|
CLEANUP:
|
|
|
|
//Should be able to release command accessor before rowset
|
|
//is released in this case, since this command accessor
|
|
//isn't being used by the rowset
|
|
if (m_hAccessor != DB_NULL_HACCESSOR && m_pCmdIAccessor)
|
|
{
|
|
CHECK(m_pCmdIAccessor->ReleaseAccessor(m_hAccessor, NULL),S_OK);
|
|
m_hAccessor = DB_NULL_HACCESSOR;
|
|
}
|
|
if (m_hAccessor2 != DB_NULL_HACCESSOR && m_pIAccessor)
|
|
{
|
|
CHECK(m_pIAccessor->ReleaseAccessor(m_hAccessor2, NULL),S_OK);
|
|
m_hAccessor2 = DB_NULL_HACCESSOR;
|
|
}
|
|
|
|
PROVIDER_FREE(m_rgBindings2);
|
|
PROVIDER_FREE(pData);
|
|
|
|
if (m_hRow && m_fIRowset)
|
|
{
|
|
m_pIRowset->ReleaseRows(1, &m_hRow, NULL, NULL, NULL);
|
|
m_hRow = DB_NULL_HROW;
|
|
}
|
|
|
|
CleanUpRowsetObject();
|
|
|
|
return (fSuccess) ? TEST_PASS : TEST_FAIL;
|
|
|
|
}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(7)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc ReleaseAccessor at different times
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCAccessorSequencing::Variation_7()
|
|
{
|
|
|
|
BOOL fSuccess = FALSE;
|
|
DBORDINAL cCols;
|
|
ULONG ulRefCount = 0;
|
|
|
|
if (!g_fCmdSupported)
|
|
{
|
|
//provider does not support commands
|
|
odtLog << wszCommandNotSupported;
|
|
return TEST_SKIPPED;
|
|
}
|
|
|
|
TESTC_(OpenRowsetObject(FALSE), S_OK);
|
|
|
|
// Release the rowset but leave the command object
|
|
SAFE_RELEASE(m_pIRowset);
|
|
SAFE_RELEASE(m_pIAccessor);
|
|
SAFE_FREE(m_rgTableColOrds);
|
|
|
|
//Create an accessor on the command object, using
|
|
//binding info generated in init, which binds all cols.
|
|
//This way we get coverage before a command is set
|
|
if (!CHECK(m_pCmdIAccessor->CreateAccessor(DBACCESSOR_ROWDATA, m_cBindings, m_rgBindings,
|
|
m_cbRowSize, &m_hAccessor, NULL), S_OK))
|
|
goto CLEANUP;
|
|
|
|
//Try release here
|
|
if (!CHECK(m_pCmdIAccessor->ReleaseAccessor(m_hAccessor, &ulRefCount), S_OK))
|
|
{
|
|
COMPARE(ulRefCount, 0);
|
|
goto CLEANUP;
|
|
}
|
|
else
|
|
m_hAccessor = DB_NULL_HACCESSOR;
|
|
|
|
//Set command, but don't execute
|
|
if (!CHECK(m_pTable->ExecuteCommand(SELECT_VALIDATIONORDER,
|
|
IID_IRowset, NULL, NULL, &cCols, &m_rgTableColOrds, EXECUTE_NEVER,
|
|
0, NULL, NULL, NULL, &m_pICommand), S_OK))
|
|
goto CLEANUP;
|
|
|
|
//Create an accessor on the command object with the command set
|
|
if (!CHECK(GetAccessorAndBindings(m_pCmdIAccessor,
|
|
DBACCESSOR_ROWDATA, &m_hAccessor, NULL,
|
|
NULL, NULL, DBPART_VALUE |
|
|
DBPART_STATUS | DBPART_LENGTH,
|
|
ALL_COLS_BOUND,
|
|
FORWARD, NO_COLS_BY_REF, NULL, NULL,
|
|
NULL, DBTYPE_EMPTY, 0, NULL, NULL,
|
|
NO_COLS_OWNED_BY_PROV, DBPARAMIO_NOTPARAM,
|
|
m_fBindLongCols),S_OK))
|
|
goto CLEANUP;
|
|
|
|
//Try release here
|
|
if (!CHECK(m_pCmdIAccessor->ReleaseAccessor(m_hAccessor, NULL), S_OK))
|
|
goto CLEANUP;
|
|
else
|
|
m_hAccessor = DB_NULL_HACCESSOR;
|
|
|
|
//Now get another one before executing
|
|
if (!CHECK(GetAccessorAndBindings(m_pCmdIAccessor,
|
|
DBACCESSOR_ROWDATA, &m_hAccessor, NULL,
|
|
NULL, NULL, DBPART_VALUE |
|
|
DBPART_STATUS | DBPART_LENGTH,
|
|
ALL_COLS_BOUND,
|
|
FORWARD, NO_COLS_BY_REF, NULL, NULL,
|
|
NULL, DBTYPE_EMPTY, 0, NULL, NULL,
|
|
NO_COLS_OWNED_BY_PROV, DBPARAMIO_NOTPARAM,
|
|
m_fBindLongCols),S_OK))
|
|
goto CLEANUP;
|
|
|
|
TESTC_(OpenRowsetObject(FALSE), S_OK);
|
|
|
|
//Releasing command accessor with open rowset should succeed.
|
|
//Note we intentionally will not release this accessor on the
|
|
//rowset object, to verify that nothing nasty happens when
|
|
//the rowset is released with rowset accessors still around.
|
|
//The rowset accessors should just be implicitly released at that point.
|
|
if (!CHECK(m_pCmdIAccessor->ReleaseAccessor(m_hAccessor, NULL), S_OK))
|
|
goto CLEANUP;
|
|
|
|
TESTC_(OpenRowsetObject(FALSE), S_OK);
|
|
|
|
//Create an accessor on the command after the execute
|
|
if (!CHECK(m_pCmdIAccessor->CreateAccessor(DBACCESSOR_ROWDATA, m_cBindings, m_rgBindings,
|
|
m_cbRowSize, &m_hAccessor, NULL), S_OK))
|
|
goto CLEANUP;
|
|
|
|
m_hAccessor = DB_NULL_HACCESSOR;
|
|
|
|
//Create an accessor on the rowset after the execute
|
|
if (!CHECK(GetAccessorAndBindings(m_pIAccessor,
|
|
DBACCESSOR_ROWDATA, &m_hAccessor2, NULL,
|
|
NULL, NULL, DBPART_VALUE |
|
|
DBPART_STATUS | DBPART_LENGTH,
|
|
ALL_COLS_BOUND,
|
|
FORWARD, NO_COLS_BY_REF, NULL, NULL,
|
|
NULL, DBTYPE_EMPTY, 0, NULL, NULL,
|
|
NO_COLS_OWNED_BY_PROV, DBPARAMIO_NOTPARAM,
|
|
m_fBindLongCols),S_OK))
|
|
goto CLEANUP;
|
|
|
|
|
|
//Try release here
|
|
if (!CHECK(m_pIAccessor->ReleaseAccessor(m_hAccessor2, NULL), S_OK))
|
|
goto CLEANUP;
|
|
|
|
m_hAccessor2 = DB_NULL_HACCESSOR;
|
|
|
|
//If we got this far, we succeeded
|
|
fSuccess = TRUE;
|
|
|
|
CLEANUP:
|
|
|
|
//Try release here,
|
|
CleanUpRowsetObject();
|
|
|
|
return (fSuccess) ? TEST_PASS : TEST_FAIL;
|
|
|
|
}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(8)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc Use Command accessor after freeing command object
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCAccessorSequencing::Variation_8()
|
|
{
|
|
BOOL fSuccess = FALSE;
|
|
DBCOUNTITEM cCommandBindings = 0;
|
|
|
|
if (!g_fCmdSupported)
|
|
{
|
|
//provider does not support commands
|
|
odtLog << wszCommandNotSupported;
|
|
return TEST_SKIPPED;
|
|
}
|
|
|
|
//Make this none zero so we know it changed to the expected zero value
|
|
ULONG ulRefCount = 1;
|
|
|
|
TESTC_(OpenRowsetObject(FALSE), S_OK);
|
|
|
|
// Release the rowset but leave the command object
|
|
SAFE_RELEASE(m_pIRowset);
|
|
SAFE_RELEASE(m_pIAccessor);
|
|
FREE_BINDINGS(&m_cBindings, &m_rgBindings);
|
|
|
|
//Set command, but don't execute, just so we can call IColumnsInfo
|
|
if (!CHECK(m_pTable->ExecuteCommand(SELECT_VALIDATIONORDER,
|
|
IID_IRowset, NULL, NULL, NULL, NULL, EXECUTE_NEVER,
|
|
0, NULL, NULL, NULL, &m_pICommand), S_OK))
|
|
goto CLEANUP;
|
|
|
|
|
|
//Create a command object accessor
|
|
if (!CHECK(GetAccessorAndBindings(m_pCmdIAccessor,
|
|
DBACCESSOR_ROWDATA, &m_hAccessor, &m_rgBindings, &m_cBindings, &m_cbRowSize,
|
|
DBPART_VALUE | DBPART_STATUS | DBPART_LENGTH,
|
|
ALL_COLS_BOUND,
|
|
FORWARD, NO_COLS_BY_REF, NULL, NULL,
|
|
NULL, DBTYPE_EMPTY, 0, NULL, NULL,
|
|
NO_COLS_OWNED_BY_PROV, DBPARAMIO_NOTPARAM,
|
|
m_fBindLongCols),S_OK))
|
|
goto CLEANUP;
|
|
|
|
cCommandBindings = m_cBindings;
|
|
|
|
|
|
TESTC_(OpenRowsetObject(FALSE), S_OK);
|
|
|
|
// Release IAccessor interface obtained in CreateRowsetObject so we won't overwrite it below
|
|
SAFE_RELEASE(m_pIAccessor);
|
|
|
|
m_pICommand->Execute(NULL, IID_IAccessor, NULL, NULL, (IUnknown **)&m_pIAccessor);
|
|
|
|
//Try to get an IRowset interface
|
|
SAFE_RELEASE(m_pIRowset);
|
|
if(VerifyInterface(m_pIAccessor,IID_IRowset, ROWSET_INTERFACE,
|
|
(IUnknown **)&m_pIRowset))
|
|
{
|
|
//Record that IRowset is supported
|
|
m_fIRowset = TRUE;
|
|
}
|
|
else
|
|
goto CLEANUP;
|
|
|
|
|
|
//Now command object should be releaseable, command accessor should
|
|
//go away with no problem, but inherited accessor should still work
|
|
SAFE_RELEASE(m_pCmdIAccessor);
|
|
SAFE_RELEASE(m_pICommand);
|
|
|
|
// At this point m_cBindings contains the number of bindings from the ROWSET.
|
|
// If this is different than we got on the command above, then it's a provider
|
|
// bug, but we won't be able to validate data.
|
|
TESTC(cCommandBindings == m_cBindings);
|
|
|
|
if(g_fCmdSupported)
|
|
{
|
|
//We should still be able to use the accessor we created on command object
|
|
if (S_OK != UseRowAccessorAndVerify(m_hAccessor, m_cbRowSize, g_uiRowNum,
|
|
m_rgTableColOrds, m_cBindings, m_rgBindings, m_cBindings))
|
|
goto CLEANUP;
|
|
}
|
|
|
|
if (!VerifyBindings(m_pIAccessor, m_rgBindings, m_cBindings, m_hAccessor,
|
|
DBACCESSOR_ROWDATA))
|
|
goto CLEANUP;
|
|
|
|
//We should also be able to release this inherited accessor
|
|
if (!CHECK(m_pIAccessor->ReleaseAccessor(m_hAccessor, &ulRefCount), S_OK))
|
|
goto CLEANUP;
|
|
|
|
COMPARE(ulRefCount, 0);
|
|
m_hAccessor = DB_NULL_HACCESSOR;
|
|
|
|
//If we got this far, we have succeeded
|
|
fSuccess = TRUE;
|
|
|
|
CLEANUP:
|
|
|
|
CleanUpRowsetObject();
|
|
|
|
//Get a command object back for any subsequent variations
|
|
CHECK(CreateCommandObject(), S_OK);
|
|
|
|
// Some providers can't retrieve BLOB data without IRowsetLocate on, so here
|
|
// we turn back on since we lost it when recreating the command object.
|
|
if (m_fBindLongCols == BLOB_LONG && SupportedProperty(DBPROP_IRowsetLocate, DBPROPSET_ROWSET, m_pThisTestModule->m_pIUnknown,SESSION_INTERFACE))
|
|
CHECK(SetRowsetProperty(m_pICommand, DBPROPSET_ROWSET, DBPROP_IRowsetLocate, TRUE), S_OK);
|
|
|
|
return (fSuccess) ? TEST_PASS : TEST_FAIL;
|
|
}
|
|
// }}
|
|
|
|
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(9)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc CreateAccessor from GetBindings and Release, validate pBinding
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCAccessorSequencing::Variation_9()
|
|
{
|
|
BOOL fResults = FALSE;
|
|
DBBINDING * pBinding = NULL;
|
|
|
|
TESTC_(OpenRowsetObject(TRUE), S_OK);
|
|
|
|
// Save a copy of the binding info for later comparison
|
|
SAFE_ALLOC(pBinding, DBBINDING, m_cBindings * sizeof(DBBINDING));
|
|
memcpy(pBinding, m_rgBindings, (size_t)(m_cBindings * sizeof(DBBINDING)));
|
|
|
|
if (g_fCmdSupported)
|
|
{
|
|
TESTC_(m_pCmdIAccessor->CreateAccessor(DBACCESSOR_ROWDATA, m_cBindings,
|
|
pBinding, m_cbRowSize, &m_hAccessor, m_rgStatus), S_OK);
|
|
|
|
// Call GetBindings and validate the binding information remains the same
|
|
if (!VerifyBindings(m_pCmdIAccessor, pBinding, m_cBindings, m_hAccessor, DBACCESSOR_ROWDATA))
|
|
goto CLEANUP;
|
|
|
|
SAFE_RELEASE_ACCESSOR(m_pCmdIAccessor, m_hAccessor);
|
|
|
|
// Now release the accessor, bindings should remain the same
|
|
TESTC(memcmp(pBinding, m_rgBindings,(size_t)(m_cBindings * sizeof(DBBINDING))) == 0);
|
|
|
|
}
|
|
|
|
// Now do the same thing for a rowset accessor
|
|
|
|
//Null phAccessor should return invalid arg
|
|
TESTC_(m_pIAccessor->CreateAccessor(DBACCESSOR_ROWDATA, m_cBindings,
|
|
pBinding, m_cbRowSize, &m_hAccessor, m_rgStatus), S_OK);
|
|
|
|
// Call GetBindings and validate the binding information remains the same
|
|
if (!VerifyBindings(m_pIAccessor, pBinding, m_cBindings, m_hAccessor, DBACCESSOR_ROWDATA))
|
|
goto CLEANUP;
|
|
|
|
SAFE_RELEASE_ACCESSOR(m_pIAccessor, m_hAccessor);
|
|
|
|
// Now release the accessor, bindings should remain the same
|
|
TESTC(memcmp(pBinding, m_rgBindings, (size_t)(m_cBindings * sizeof(DBBINDING))) == 0);
|
|
|
|
fResults = TRUE;
|
|
|
|
CLEANUP:
|
|
|
|
SAFE_FREE(pBinding);
|
|
|
|
return (fResults) ? TEST_PASS : TEST_FAIL;
|
|
|
|
}
|
|
// }} TCW_VAR_PROTOTYPE_END
|
|
|
|
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(10)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc CreateAccessor on new command object
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCAccessorSequencing::Variation_10()
|
|
{
|
|
BOOL fSuccess = TEST_FAIL;
|
|
DBORDINAL cCols;
|
|
ICommand * pICommand = NULL;
|
|
IAccessor * pIAccessor = NULL;
|
|
IRowset * pISaveRowset = m_pIRowset;
|
|
HACCESSOR hAccessor = DB_NULL_HACCESSOR;
|
|
DB_LORDINAL * pTableColOrds = NULL;
|
|
|
|
if (!g_fCmdSupported)
|
|
{
|
|
//provider does not support commands
|
|
odtLog << wszCommandNotSupported;
|
|
return TEST_SKIPPED;
|
|
}
|
|
|
|
// Create a new command object, don't set any command text.
|
|
TESTC_(m_pIDBCreateCommand->CreateCommand(NULL, IID_ICommand, (IUnknown **)&pICommand), S_OK);
|
|
|
|
// Some providers can't retrieve BLOB data without IRowsetLocate on.
|
|
if (m_fBindLongCols == BLOB_LONG && SupportedProperty(DBPROP_IRowsetLocate, DBPROPSET_ROWSET, m_pThisTestModule->m_pIUnknown,SESSION_INTERFACE))
|
|
TESTC_(SetRowsetProperty(pICommand, DBPROPSET_ROWSET, DBPROP_IRowsetLocate, TRUE), S_OK);
|
|
|
|
// Get an accessor interface
|
|
TESTC(VerifyInterface(pICommand, IID_IAccessor, COMMAND_INTERFACE,
|
|
(IUnknown **)&pIAccessor));
|
|
|
|
// Create an accessor using our known bindings
|
|
TESTC_(pIAccessor->CreateAccessor(DBACCESSOR_ROWDATA, m_cBindings,
|
|
m_rgBindings, m_cbRowSize, &hAccessor, m_rgStatus), S_OK);
|
|
|
|
//Make sure we can do GetBindings at this point
|
|
TESTC(VerifyBindings(pIAccessor, m_rgBindings, m_cBindings, hAccessor,
|
|
DBACCESSOR_ROWDATA));
|
|
|
|
TESTC_(m_pTable->ExecuteCommand(SELECT_VALIDATIONORDER,
|
|
IID_IRowset, NULL, NULL, &cCols, &pTableColOrds, EXECUTE_NEVER,
|
|
0, NULL, NULL, NULL, &pICommand), S_OK);
|
|
|
|
//Execute command
|
|
TESTC_(pICommand->Execute(NULL, IID_IRowset, NULL,
|
|
NULL, (IUnknown **)&m_pIRowset),S_OK);
|
|
|
|
//Now use accessor
|
|
TESTC_(UseRowAccessorAndVerify(hAccessor, m_cbRowSize, g_uiRowNum,
|
|
pTableColOrds, cCols, m_rgBindings, m_cBindings),S_OK);
|
|
|
|
fSuccess = TEST_PASS;
|
|
|
|
CLEANUP:
|
|
|
|
SAFE_RELEASE_ACCESSOR(pIAccessor, hAccessor);
|
|
SAFE_RELEASE(m_pIRowset);
|
|
SAFE_RELEASE(pICommand);
|
|
SAFE_RELEASE(pIAccessor);
|
|
SAFE_FREE(pTableColOrds);
|
|
m_pIRowset = pISaveRowset;
|
|
|
|
return fSuccess;
|
|
}
|
|
// }} TCW_VAR_PROTOTYPE_END
|
|
|
|
|
|
// {{ TCW_TERMINATE_METHOD
|
|
//--------------------------------------------------------------------
|
|
// @mfunc TestCase Termination Routine
|
|
//
|
|
// @rdesc TRUE or FALSE
|
|
//
|
|
BOOL TCAccessorSequencing::Terminate()
|
|
{
|
|
CleanUpRowsetObject();
|
|
|
|
// {{ TCW_TERM_BASECLASS_CHECK2
|
|
return(CAccessor::Terminate());
|
|
} // }}
|
|
// }}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_TC_PROTOTYPE(TCBookMarkRowset)
|
|
//*-----------------------------------------------------------------------
|
|
//| Test Case: TCBookMarkRowset - Create accessors for rowsets with bookmarks
|
|
//| Created: 11/14/95
|
|
//*-----------------------------------------------------------------------
|
|
|
|
//--------------------------------------------------------------------
|
|
// @mfunc TestCase Initialization Routine
|
|
//
|
|
// @rdesc TRUE or FALSE
|
|
//
|
|
BOOL TCBookMarkRowset::Init()
|
|
{
|
|
// {{ TCW_INIT_BASECLASS_CHECK
|
|
if(CAccessor::Init())
|
|
// }}
|
|
{
|
|
DBPROPSET DBPropSet;
|
|
DBPROP Prop;
|
|
|
|
//Set IRowsetLocate properties to try to create rowset with bookmarks
|
|
|
|
Prop.dwPropertyID = DBPROP_IRowsetLocate;
|
|
Prop.dwOptions = DBPROPOPTIONS_REQUIRED;
|
|
Prop.colid = DB_NULLID;
|
|
Prop.vValue.vt = VT_BOOL;
|
|
V_BOOL(&(Prop.vValue)) = VARIANT_TRUE;
|
|
|
|
//Set up our property set for rowset properties
|
|
DBPropSet.guidPropertySet = DBPROPSET_ROWSET;
|
|
DBPropSet.rgProperties = &Prop;
|
|
DBPropSet.cProperties = 1;
|
|
|
|
SetRowsetProperties(&DBPropSet, 1);
|
|
|
|
//Set m_pIAccessor on a 'select *' rowset with bookmarks
|
|
m_hr=CreateRowsetObject(SELECT_VALIDATIONORDER);
|
|
|
|
if (SUCCEEDED(m_hr))
|
|
{
|
|
//If we got an S code, it should be S_OK
|
|
if (CHECK(m_hr, S_OK))
|
|
//This is the only condition in which
|
|
//the following testcases should be run
|
|
return TRUE;
|
|
|
|
}
|
|
//If we got any error, the only acceptable one
|
|
//is that IRowsetLocate is not supported
|
|
else
|
|
{
|
|
if (CHECK(m_hr, DB_E_ERRORSOCCURRED))
|
|
{
|
|
//Check the array which the provider was passed by our framework
|
|
//to see what status the provider gave
|
|
if (COMPARE(m_rgPropSets[0].rgProperties[0].dwStatus, DBPROPSTATUS_NOTSUPPORTED))
|
|
{
|
|
odtLog << L"IRowsetLocate not supported by provider, this variation is not applicable.\n";
|
|
return TEST_SKIPPED;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(1)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc Bind bookmark column with ROWDATA
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCBookMarkRowset::Variation_1()
|
|
{
|
|
|
|
BOOL fSuccess = FALSE;
|
|
|
|
|
|
//We know we support IRowset since we got IRowsetLocate in Init
|
|
m_fIRowset = TRUE;
|
|
if (!VerifyInterface(m_pIAccessor, IID_IRowset, ROWSET_INTERFACE,(IUnknown **)&m_pIRowset))
|
|
return TEST_FAIL;
|
|
|
|
//Bind all columns, including col 0
|
|
if (CHECK(GetAccessorAndBindings(m_pIAccessor,
|
|
DBACCESSOR_ROWDATA,
|
|
&m_hAccessor, &m_rgBindings, &m_cBindings, &m_cbRowSize,
|
|
DBPART_VALUE | DBPART_STATUS | DBPART_LENGTH,
|
|
ALL_COLS_BOUND,
|
|
FORWARD, NO_COLS_BY_REF, NULL, NULL,
|
|
NULL, DBTYPE_EMPTY, 0, NULL, NULL,
|
|
NO_COLS_OWNED_BY_PROV, DBPARAMIO_NOTPARAM,
|
|
m_fBindLongCols),S_OK))
|
|
{
|
|
|
|
//Verify the data is correctly brought back using the accessor
|
|
//(via either GetData or ReadData) - note this function also
|
|
//validates that the bookmark retrieved is valid
|
|
if (CHECK(UseRowAccessorAndVerify(m_hAccessor, m_cbRowSize, g_uiRowNum,
|
|
m_rgTableColOrds, m_cRowsetCols, m_rgBindings, m_cBindings),S_OK))
|
|
//Check accessor with GetBindings
|
|
fSuccess = VerifyBindings(m_pIAccessor, m_rgBindings, m_cBindings, m_hAccessor,
|
|
DBACCESSOR_ROWDATA);
|
|
}
|
|
|
|
//Clean up
|
|
if (m_hAccessor)
|
|
CHECK(m_pIAccessor->ReleaseAccessor(m_hAccessor, NULL),S_OK);
|
|
|
|
FREE_BINDINGS(&m_cBindings, &m_rgBindings);
|
|
SAFE_RELEASE(m_pIRowset);
|
|
|
|
if (fSuccess)
|
|
return TEST_PASS;
|
|
else
|
|
return TEST_FAIL;
|
|
|
|
}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_TERMINATE_METHOD
|
|
//--------------------------------------------------------------------
|
|
// @mfunc TestCase Termination Routine
|
|
//
|
|
// @rdesc TRUE or FALSE
|
|
//
|
|
BOOL TCBookMarkRowset::Terminate()
|
|
{
|
|
|
|
ReleaseRowsetObject();
|
|
|
|
// {{ TCW_TERM_BASECLASS_CHECK2
|
|
return(CAccessor::Terminate());
|
|
} // }}
|
|
// }}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_TC_PROTOTYPE(TCGetBindingsRtnVals)
|
|
//*-----------------------------------------------------------------------
|
|
//| Test Case: TCGetBindingsRtnVals - Return values for all GetBindings error conditions
|
|
//| Created: 11/24/95
|
|
//*-----------------------------------------------------------------------
|
|
|
|
//--------------------------------------------------------------------
|
|
// @mfunc TestCase Initialization Routine
|
|
//
|
|
// @rdesc TRUE or FALSE
|
|
//
|
|
BOOL TCGetBindingsRtnVals::Init()
|
|
{
|
|
BOOL fSuccess = FALSE;
|
|
HRESULT hr;
|
|
|
|
// {{ TCW_INIT_BASECLASS_CHECK
|
|
if(CAccessor::Init())
|
|
// }}
|
|
{
|
|
//Set m_pIAccessor on a 'select *' rowset We'll
|
|
//use this interface ptr to do our tests.
|
|
hr=CreateRowsetObject(SELECT_VALIDATIONORDER);
|
|
|
|
if (CHECK(hr,S_OK))
|
|
{
|
|
//ReleaseRowsetObject();
|
|
if(m_pICommand)
|
|
{
|
|
ReleaseRowsetObject();
|
|
//Try to get IAccesor on Command
|
|
if (VerifyInterface(m_pICommand,IID_IAccessor,COMMAND_INTERFACE,
|
|
(IUnknown **)&m_pCmdIAccessor))
|
|
{
|
|
//Create an accessor on the command object
|
|
if (CHECK(GetAccessorAndBindings(m_pCmdIAccessor, DBACCESSOR_ROWDATA,
|
|
&m_hAccessor, &m_rgBindings, &m_cBindings, &m_cbRowSize,
|
|
DBPART_VALUE | DBPART_LENGTH | DBPART_STATUS,
|
|
ALL_COLS_BOUND,
|
|
FORWARD, NO_COLS_BY_REF, NULL, NULL,
|
|
NULL, DBTYPE_EMPTY, 0, NULL, NULL,
|
|
NO_COLS_OWNED_BY_PROV, DBPARAMIO_NOTPARAM,
|
|
m_fBindLongCols),S_OK))
|
|
{
|
|
if (!CHECK(CreateRowsetObject(SELECT_VALIDATIONORDER),S_OK))
|
|
return TEST_FAIL;
|
|
}
|
|
}
|
|
}
|
|
//Create an accessor on the rowset object
|
|
if (CHECK(GetAccessorAndBindings(m_pIAccessor, DBACCESSOR_ROWDATA,
|
|
&m_hAccessor2, &m_rgBindings2, &m_cBindings2, &m_cbRowSize2,
|
|
DBPART_VALUE | DBPART_LENGTH | DBPART_STATUS,
|
|
ALL_COLS_BOUND,
|
|
FORWARD, NO_COLS_BY_REF, NULL, NULL,
|
|
NULL, DBTYPE_EMPTY, 0, NULL, NULL,
|
|
NO_COLS_OWNED_BY_PROV, DBPARAMIO_NOTPARAM,
|
|
m_fBindLongCols),S_OK))
|
|
fSuccess = TRUE;
|
|
}
|
|
|
|
}
|
|
|
|
FREE_BINDINGS(&m_cBindings, &m_rgBindings);
|
|
FREE_BINDINGS(&m_cBindings2, &m_rgBindings2);
|
|
|
|
return fSuccess;
|
|
}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(1)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc E_INVALIDARG - Null pdwAccessorFlags
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCGetBindingsRtnVals::Variation_1()
|
|
{
|
|
BOOL fSuccess = TRUE;
|
|
m_cBindings = 8;
|
|
m_rgBindings = (DBBINDING *)&m_rgBindings;
|
|
|
|
//Try GetBindings on command object, if its supported
|
|
if (m_pCmdIAccessor)
|
|
{
|
|
fSuccess = CHECK(m_pCmdIAccessor->GetBindings(m_hAccessor, NULL,
|
|
&m_cBindings, &m_rgBindings), E_INVALIDARG);
|
|
//Parameters must be set to 0 and NULL on error
|
|
fSuccess &= COMPARE(m_cBindings, 0);
|
|
fSuccess &= COMPARE(m_rgBindings, NULL);
|
|
}
|
|
|
|
m_cBindings = 8;
|
|
m_rgBindings = (DBBINDING *)&m_rgBindings;
|
|
|
|
//Now do GetBindings on rowset object
|
|
fSuccess &= CHECK(m_pIAccessor->GetBindings(m_hAccessor2, NULL,
|
|
&m_cBindings, &m_rgBindings), E_INVALIDARG);
|
|
//Parameters must be set to 0 and NULL on error
|
|
fSuccess &= COMPARE(m_cBindings, 0);
|
|
fSuccess &= COMPARE(m_rgBindings, NULL);
|
|
|
|
m_cBindings = 0;
|
|
m_rgBindings = NULL;
|
|
|
|
|
|
if (fSuccess)
|
|
return TEST_PASS;
|
|
else
|
|
return TEST_FAIL;
|
|
}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(2)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc E_INVALIDARG - Null pcBindings
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCGetBindingsRtnVals::Variation_2()
|
|
{
|
|
|
|
DBACCESSORFLAGS dwFlags = 1;
|
|
BOOL fSuccess = TRUE;
|
|
m_rgBindings = (DBBINDING *)&m_rgBindings;
|
|
|
|
//Try GetBindings on command object, if its supported
|
|
if (m_pCmdIAccessor)
|
|
{
|
|
fSuccess = CHECK(m_pCmdIAccessor->GetBindings(m_hAccessor, &dwFlags,
|
|
NULL, &m_rgBindings), E_INVALIDARG);
|
|
//Parameters must be set to 0 and NULL on error
|
|
fSuccess &= COMPARE(dwFlags, DBACCESSOR_INVALID);
|
|
fSuccess &= COMPARE(m_rgBindings, NULL);
|
|
}
|
|
|
|
//Reset to 1 so we are sure that method sets it to zero
|
|
dwFlags = 1;
|
|
|
|
m_rgBindings = (DBBINDING *)&m_rgBindings;
|
|
|
|
//Now do GetBindings on rowset object
|
|
fSuccess &= CHECK(m_pIAccessor->GetBindings(m_hAccessor2, &dwFlags,
|
|
NULL, &m_rgBindings), E_INVALIDARG);
|
|
//Parameters must be set to 0 and NULL on error
|
|
fSuccess &= COMPARE(dwFlags, DBACCESSOR_INVALID);
|
|
fSuccess &= COMPARE(m_rgBindings, NULL);
|
|
|
|
m_rgBindings = NULL;
|
|
|
|
if (fSuccess)
|
|
return TEST_PASS;
|
|
else
|
|
return TEST_FAIL;
|
|
}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(3)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc E_INVALIDARG - Null prgBindings
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCGetBindingsRtnVals::Variation_3()
|
|
{
|
|
DBACCESSORFLAGS dwFlags = 1;
|
|
BOOL fSuccess = TRUE;
|
|
m_cBindings = 8;
|
|
|
|
|
|
//Try GetBindings on command object, if its supported
|
|
if (m_pCmdIAccessor)
|
|
{
|
|
fSuccess = CHECK(m_pCmdIAccessor->GetBindings(m_hAccessor, &dwFlags,
|
|
&m_cBindings, NULL), E_INVALIDARG);
|
|
//Parameters must be set to 0 and NULL on error
|
|
fSuccess &= COMPARE(dwFlags, DBACCESSOR_INVALID);
|
|
fSuccess &= COMPARE(m_cBindings, 0);
|
|
}
|
|
|
|
//Reset to 1 so we are sure that method sets it to zero
|
|
dwFlags = 1;
|
|
m_cBindings = 8;
|
|
|
|
//Now do GetBindings on rowset object
|
|
fSuccess &= CHECK(m_pIAccessor->GetBindings(m_hAccessor2, &dwFlags,
|
|
&m_cBindings, NULL), E_INVALIDARG);
|
|
//Parameters must be set to 0 and NULL on error
|
|
fSuccess &= COMPARE(dwFlags, DBACCESSOR_INVALID);
|
|
fSuccess &= COMPARE(m_cBindings, 0);
|
|
|
|
m_cBindings = 0;
|
|
|
|
|
|
if (fSuccess)
|
|
return TEST_PASS;
|
|
else
|
|
return TEST_FAIL;
|
|
}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(4)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc DB_E_BADACCESSORHANDLE - Null hAccessor
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCGetBindingsRtnVals::Variation_4()
|
|
{
|
|
DBACCESSORFLAGS dwFlags = 1;
|
|
BOOL fSuccess = TRUE;
|
|
m_cBindings = 8;
|
|
m_rgBindings = (DBBINDING *)&m_rgBindings;
|
|
|
|
//Try GetBindings on command object, if its supported
|
|
if (m_pCmdIAccessor)
|
|
{
|
|
fSuccess = CHECK(m_pCmdIAccessor->GetBindings(NULL, &dwFlags,
|
|
&m_cBindings, &m_rgBindings), DB_E_BADACCESSORHANDLE);
|
|
//Parameters must be set to 0 and NULL on error
|
|
fSuccess &= COMPARE(dwFlags, DBACCESSOR_INVALID);
|
|
fSuccess &= COMPARE(m_rgBindings, NULL);
|
|
fSuccess &= COMPARE(m_cBindings, 0);
|
|
}
|
|
|
|
//Reset to 1 so we are sure that method sets it to zero
|
|
dwFlags = 1;
|
|
m_cBindings = 8;
|
|
m_rgBindings = (DBBINDING *)&m_rgBindings;
|
|
|
|
//Now do GetBindings on rowset object
|
|
fSuccess &= CHECK(m_pIAccessor->GetBindings(NULL, &dwFlags,
|
|
&m_cBindings, &m_rgBindings), DB_E_BADACCESSORHANDLE);
|
|
//Parameters must be set to 0 and NULL on error
|
|
fSuccess &= COMPARE(dwFlags, DBACCESSOR_INVALID);
|
|
fSuccess &= COMPARE(m_rgBindings, NULL);
|
|
fSuccess &= COMPARE(m_cBindings, 0);
|
|
|
|
m_cBindings = 0;
|
|
m_rgBindings = NULL;
|
|
|
|
if (fSuccess)
|
|
return TEST_PASS;
|
|
else
|
|
return TEST_FAIL;
|
|
}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(5)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc DB_E_BADACCESSORHANDLE - Previously released accessor for hAccessor
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCGetBindingsRtnVals::Variation_5()
|
|
{
|
|
DBACCESSORFLAGS dwFlags = 1;
|
|
BOOL fSuccess = TRUE;
|
|
m_cBindings = 8;
|
|
m_rgBindings = (DBBINDING *)&m_rgBindings;
|
|
|
|
|
|
//Release the accessor
|
|
CHECK(m_pIAccessor->ReleaseAccessor(m_hAccessor2, NULL),S_OK);
|
|
|
|
//Now do GetBindings on rowset object
|
|
fSuccess &= CHECK(m_pIAccessor->GetBindings(m_hAccessor2, &dwFlags,
|
|
&m_cBindings, &m_rgBindings), DB_E_BADACCESSORHANDLE);
|
|
//Parameters must be set to 0 and NULL on error
|
|
fSuccess &= COMPARE(dwFlags, DBACCESSOR_INVALID);
|
|
fSuccess &= COMPARE(m_rgBindings, NULL);
|
|
fSuccess &= COMPARE(m_cBindings, 0);
|
|
|
|
//Set to null so we don't release again in terminate
|
|
m_hAccessor2 = DB_NULL_HACCESSOR;
|
|
|
|
//Reset to 1 so we are sure that method sets it to zero
|
|
dwFlags = 1;
|
|
|
|
//Try GetBindings on command object, if its supported
|
|
if (m_pCmdIAccessor)
|
|
{
|
|
//First release rowset so we don't get an open object error
|
|
ReleaseRowsetObject();
|
|
|
|
//Release the accessor
|
|
CHECK(m_pCmdIAccessor->ReleaseAccessor(m_hAccessor, NULL), S_OK);
|
|
|
|
m_cBindings = 8;
|
|
m_rgBindings = (DBBINDING *)&m_rgBindings;
|
|
|
|
fSuccess &= CHECK(m_pCmdIAccessor->GetBindings(m_hAccessor, &dwFlags,
|
|
&m_cBindings, &m_rgBindings), DB_E_BADACCESSORHANDLE);
|
|
//Parameters must be set to 0 and NULL on error
|
|
fSuccess &= COMPARE(dwFlags, DBACCESSOR_INVALID);
|
|
fSuccess &= COMPARE(m_rgBindings, NULL);
|
|
fSuccess &= COMPARE(m_cBindings, 0);
|
|
|
|
//Set to null so we don't release again in terminate
|
|
m_hAccessor = DB_NULL_HACCESSOR;
|
|
//Set us up for next variation
|
|
CHECK(CreateRowsetObject(SELECT_VALIDATIONORDER),S_OK);
|
|
}
|
|
|
|
//Set us up for next variation
|
|
m_cBindings = 0;
|
|
m_rgBindings = NULL;
|
|
|
|
if (fSuccess)
|
|
return TEST_PASS;
|
|
else
|
|
return TEST_FAIL;
|
|
}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_TERMINATE_METHOD
|
|
//--------------------------------------------------------------------
|
|
// @mfunc TestCase Termination Routine
|
|
//
|
|
// @rdesc TRUE or FALSE
|
|
//
|
|
BOOL TCGetBindingsRtnVals::Terminate()
|
|
{
|
|
|
|
if (m_hAccessor && m_pIAccessor)
|
|
{
|
|
m_pIAccessor->ReleaseAccessor(m_hAccessor, NULL);
|
|
m_hAccessor = DB_NULL_HACCESSOR;
|
|
}
|
|
if (m_hAccessor2 && m_pCmdIAccessor)
|
|
{
|
|
m_pCmdIAccessor->ReleaseAccessor(m_hAccessor2, NULL);
|
|
m_hAccessor2 = DB_NULL_HACCESSOR;
|
|
}
|
|
|
|
SAFE_RELEASE(m_pCmdIAccessor);
|
|
|
|
ReleaseRowsetObject();
|
|
// {{ TCW_TERM_BASECLASS_CHECK2
|
|
return(CAccessor::Terminate());
|
|
} // }}
|
|
// }}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_TC_PROTOTYPE(TCReleaseAccessorRtnVals)
|
|
//*-----------------------------------------------------------------------
|
|
//| Test Case: TCReleaseAccessorRtnVals - Return values for all ReleaseAccessor error conditions
|
|
//| Created: 11/24/95
|
|
//*-----------------------------------------------------------------------
|
|
|
|
//--------------------------------------------------------------------
|
|
// @mfunc TestCase Initialization Routine
|
|
//
|
|
// @rdesc TRUE or FALSE
|
|
//
|
|
BOOL TCReleaseAccessorRtnVals::Init()
|
|
{
|
|
BOOL fSuccess = FALSE;
|
|
HRESULT hr;
|
|
|
|
// {{ TCW_INIT_BASECLASS_CHECK
|
|
if(CAccessor::Init())
|
|
// }}
|
|
{
|
|
//Set m_pIAccessor on a 'select *' rowset We'll
|
|
//use this interface ptr to do our tests.
|
|
hr=CreateRowsetObject(SELECT_VALIDATIONORDER);
|
|
|
|
if (CHECK(hr,S_OK))
|
|
{
|
|
//Get IAccesor on Command
|
|
if(m_pICommand)
|
|
{
|
|
//Make sure we don't get Open Object error
|
|
ReleaseRowsetObject();
|
|
|
|
if (VerifyInterface(m_pICommand,IID_IAccessor,COMMAND_INTERFACE,
|
|
(IUnknown **)&m_pCmdIAccessor))
|
|
{
|
|
//Create an accessor on the command object
|
|
if (CHECK(GetAccessorAndBindings(m_pCmdIAccessor, DBACCESSOR_ROWDATA,
|
|
&m_hAccessor, &m_rgBindings, &m_cBindings, &m_cbRowSize,
|
|
DBPART_VALUE | DBPART_LENGTH | DBPART_STATUS,
|
|
ALL_COLS_BOUND,
|
|
FORWARD, NO_COLS_BY_REF, NULL, NULL,
|
|
NULL, DBTYPE_EMPTY, 0, NULL, NULL,
|
|
NO_COLS_OWNED_BY_PROV, DBPARAMIO_NOTPARAM,
|
|
m_fBindLongCols),S_OK))
|
|
{
|
|
//Now create rowset again
|
|
if (!CHECK(CreateRowsetObject(SELECT_VALIDATIONORDER),S_OK))
|
|
return TEST_FAIL;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (CHECK(GetAccessorAndBindings(m_pIAccessor, DBACCESSOR_ROWDATA,
|
|
&m_hAccessor2, &m_rgBindings2, &m_cBindings2, &m_cbRowSize2,
|
|
DBPART_VALUE | DBPART_LENGTH | DBPART_STATUS,
|
|
ALL_COLS_BOUND,
|
|
FORWARD, NO_COLS_BY_REF, NULL, NULL,
|
|
NULL, DBTYPE_EMPTY, 0, NULL, NULL,
|
|
NO_COLS_OWNED_BY_PROV, DBPARAMIO_NOTPARAM,
|
|
m_fBindLongCols),S_OK))
|
|
fSuccess = TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
return fSuccess;
|
|
}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(1)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc S_OK - Release Rowset without releasing rowset Accessor
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCReleaseAccessorRtnVals::Variation_1()
|
|
{
|
|
BOOL fSuccess = FALSE;
|
|
HRESULT hr;
|
|
|
|
//Make sure releasing the rowset cleans up the accessor without dying
|
|
ReleaseRowsetObject();
|
|
|
|
hr=CreateRowsetObject(SELECT_VALIDATIONORDER);
|
|
|
|
//Create Rowset and accessor again for next vars
|
|
if (CHECK(hr,S_OK))
|
|
{
|
|
//Create an accessor on the rowset object
|
|
if (CHECK(GetAccessorAndBindings(m_pIAccessor, DBACCESSOR_ROWDATA,
|
|
&m_hAccessor2, NULL, NULL, NULL,
|
|
DBPART_VALUE | DBPART_LENGTH | DBPART_STATUS,
|
|
ALL_COLS_BOUND,
|
|
FORWARD, NO_COLS_BY_REF, NULL, NULL,
|
|
NULL, DBTYPE_EMPTY, 0, NULL, NULL,
|
|
NO_COLS_OWNED_BY_PROV, DBPARAMIO_NOTPARAM,
|
|
m_fBindLongCols),S_OK))
|
|
fSuccess = TRUE;
|
|
}
|
|
|
|
|
|
if (fSuccess)
|
|
return TEST_PASS;
|
|
else
|
|
return TEST_FAIL;
|
|
}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(2)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc DB_E_BADACCESSORHANDLE - Previously released accessor for hAccessor
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCReleaseAccessorRtnVals::Variation_2()
|
|
{
|
|
|
|
BOOL fSuccess = TRUE;
|
|
|
|
|
|
//Do release twice on rowset object
|
|
CHECK(m_pIAccessor->ReleaseAccessor(m_hAccessor2, NULL), S_OK);
|
|
fSuccess = CHECK(m_pIAccessor->ReleaseAccessor(m_hAccessor2, NULL),
|
|
DB_E_BADACCESSORHANDLE);
|
|
|
|
if(m_pCmdIAccessor)
|
|
{
|
|
//Now close rowset so we don't get DB_E_OPENOBJECT when we release cmd accessor
|
|
ReleaseRowsetObject();
|
|
|
|
//Release same accessor twice on command object
|
|
CHECK(m_pCmdIAccessor->ReleaseAccessor(m_hAccessor, NULL), S_OK);
|
|
fSuccess &= CHECK(m_pCmdIAccessor->ReleaseAccessor(m_hAccessor, NULL),
|
|
DB_E_BADACCESSORHANDLE);
|
|
|
|
//Now create command accessor again for other variations
|
|
CHECK(GetAccessorAndBindings(m_pCmdIAccessor, DBACCESSOR_ROWDATA,
|
|
&m_hAccessor, NULL, NULL, NULL, DBPART_VALUE |
|
|
DBPART_LENGTH | DBPART_STATUS,
|
|
ALL_COLS_BOUND,
|
|
FORWARD, NO_COLS_BY_REF, NULL, NULL,
|
|
NULL, DBTYPE_EMPTY, 0, NULL, NULL,
|
|
NO_COLS_OWNED_BY_PROV, DBPARAMIO_NOTPARAM,
|
|
m_fBindLongCols),S_OK);
|
|
}
|
|
|
|
//Get rowset back for other variations
|
|
CHECK(CreateRowsetObject(SELECT_VALIDATIONORDER),S_OK);
|
|
|
|
//Now create rowset accessor again for other variations
|
|
CHECK(GetAccessorAndBindings(m_pIAccessor, DBACCESSOR_ROWDATA,
|
|
&m_hAccessor2, NULL, NULL, NULL, DBPART_VALUE |
|
|
DBPART_LENGTH | DBPART_STATUS,
|
|
ALL_COLS_BOUND,
|
|
FORWARD, NO_COLS_BY_REF, NULL, NULL,
|
|
NULL, DBTYPE_EMPTY, 0, NULL, NULL,
|
|
NO_COLS_OWNED_BY_PROV, DBPARAMIO_NOTPARAM,
|
|
m_fBindLongCols),S_OK);
|
|
|
|
|
|
if (fSuccess)
|
|
return TEST_PASS;
|
|
else
|
|
return TEST_FAIL;
|
|
}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(3)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc DB_E_OPENOBJECT - Release command accessor while rowset is open
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCReleaseAccessorRtnVals::Variation_3()
|
|
{
|
|
|
|
HACCESSOR hAccessor;
|
|
|
|
//if command is not supported
|
|
if(!m_pCmdIAccessor)
|
|
return TEST_PASS;
|
|
|
|
//Now create command accessor after rowset is already open
|
|
CHECK(m_pCmdIAccessor->CreateAccessor(DBACCESSOR_ROWDATA,
|
|
m_cBindings, m_rgBindings, m_cbRowSize,
|
|
&hAccessor, NULL),S_OK);
|
|
|
|
//Try to release command accessor while rowest is open,
|
|
//This should work because the accessor was created after
|
|
//the rowset was opened. Note, in TCAccessorSequencing
|
|
//we test releasing accessor created before rowset was opened.
|
|
if (CHECK(m_pCmdIAccessor->ReleaseAccessor(hAccessor, NULL),
|
|
S_OK))
|
|
return TEST_PASS;
|
|
else
|
|
return TEST_FAIL;
|
|
}
|
|
|
|
// }}
|
|
// {{ TCW_TERMINATE_METHOD
|
|
//--------------------------------------------------------------------
|
|
// @mfunc TestCase Termination Routine
|
|
//
|
|
// @rdesc TRUE or FALSE
|
|
//
|
|
BOOL TCReleaseAccessorRtnVals::Terminate()
|
|
{
|
|
FREE_BINDINGS(&m_cBindings, &m_rgBindings);
|
|
FREE_BINDINGS(&m_cBindings2, &m_rgBindings2);
|
|
|
|
if (m_hAccessor2 && m_pIAccessor)
|
|
{
|
|
CHECK(m_pIAccessor->ReleaseAccessor(m_hAccessor2, NULL), S_OK);
|
|
m_hAccessor2 = DB_NULL_HACCESSOR;
|
|
}
|
|
|
|
if (m_hAccessor && m_pCmdIAccessor)
|
|
{
|
|
CHECK(m_pCmdIAccessor->ReleaseAccessor(m_hAccessor, NULL), S_OK);
|
|
m_hAccessor = DB_NULL_HACCESSOR;
|
|
}
|
|
|
|
CleanUpRowsetObject();
|
|
|
|
// {{ TCW_TERM_BASECLASS_CHECK2
|
|
return(CAccessor::Terminate());
|
|
} // }}
|
|
// }}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_TC_PROTOTYPE(TCDeferredColumns)
|
|
//*-----------------------------------------------------------------------
|
|
//| Test Case: TCDeferredColumns - Use of Deferred and CacheDeferred properties
|
|
//| Created: 11/28/95
|
|
//*-----------------------------------------------------------------------
|
|
|
|
//--------------------------------------------------------------------
|
|
// @mfunc Copies test case info from this class to encapsulated CRowset
|
|
//
|
|
// @rdesc TRUE or FALSE
|
|
//
|
|
void TCDeferredColumns::CopyTestCaseInfo(CTestCases * pTC)
|
|
{
|
|
pTC->SetOwningMod(0, this->m_pThisTestModule);
|
|
}
|
|
|
|
//--------------------------------------------------------------------
|
|
// @mfunc TestCase Initialization Routine
|
|
//
|
|
// @rdesc TRUE or FALSE
|
|
//
|
|
BOOL TCDeferredColumns::Init()
|
|
{
|
|
BOOL fSuccess = FALSE;
|
|
IRowsetInfo * pIRowsetInfo = NULL;
|
|
DBPROPIDSET PropIDSet;
|
|
const ULONG cPropertyIDs = 2;
|
|
DBPROPID rgPropIDs[cPropertyIDs];
|
|
ULONG cPropSets = 0;
|
|
DBPROPSET * rgPropSets = NULL;
|
|
IColumnsInfo * pIColInfo = NULL;
|
|
DBORDINAL cColumns = 0;
|
|
DBCOLUMNINFO * rgColInfo = NULL;
|
|
WCHAR * pStr = NULL;
|
|
const ULONG cProperties = 2;
|
|
DBPROP rgProps[cProperties];
|
|
DBPROPSET DBPropSet;
|
|
HRESULT hr;
|
|
|
|
m_pSetRowset = new CSetRowsetObject((LPWSTR)gwszModuleName, m_pThisTestModule);
|
|
if (!m_pSetRowset)
|
|
return FALSE;
|
|
|
|
m_GetAllAccessor = DB_NULL_HACCESSOR;
|
|
m_SetAllAccessor = DB_NULL_HACCESSOR;
|
|
m_VariableAccessor = DB_NULL_HACCESSOR;
|
|
m_FixedAccessor = DB_NULL_HACCESSOR;
|
|
m_rgFixedBindings = NULL;
|
|
m_rgVariableBindings = NULL;
|
|
m_rgGetAllBindings = NULL;
|
|
m_rgSetAllBindings = NULL;
|
|
m_pGetIRowset = NULL;
|
|
m_pSetIRowset = NULL;
|
|
m_pSetIRowsetChange = NULL;
|
|
m_rgDBIDs = NULL;
|
|
|
|
//Set up structures for GetProperties
|
|
PropIDSet.rgPropertyIDs = rgPropIDs;
|
|
PropIDSet.cPropertyIDs = cPropertyIDs;
|
|
PropIDSet.guidPropertySet = DBPROPSET_ROWSET;
|
|
rgPropIDs[0] = DBPROP_DEFERRED;
|
|
rgPropIDs[1] = DBPROP_CACHEDEFERRED;
|
|
|
|
//Bring our encapsulated object up to speed on what
|
|
//test case info we currently have
|
|
// CopyTestCaseInfo(m_pSetRowset);
|
|
|
|
// {{ TCW_INIT_BASECLASS_CHECK
|
|
if(CAccessor::Init())
|
|
// }}
|
|
{
|
|
|
|
//Set up a Property for SetData
|
|
//We'll use this part for both rowsets
|
|
rgProps[0].dwPropertyID = DBPROP_UPDATABILITY;
|
|
rgProps[0].dwOptions = DBPROPOPTIONS_REQUIRED;
|
|
rgProps[0].colid = DB_NULLID;
|
|
rgProps[0].vValue.vt = VT_I4;
|
|
rgProps[0].vValue.lVal = DBPROPVAL_UP_CHANGE;
|
|
|
|
rgProps[1].dwPropertyID = DBPROP_IRowsetChange;
|
|
rgProps[1].dwOptions = DBPROPOPTIONS_REQUIRED;
|
|
rgProps[1].colid = DB_NULLID;
|
|
rgProps[1].vValue.vt = VT_BOOL;
|
|
V_BOOL(&(rgProps[1].vValue)) = VARIANT_TRUE;
|
|
|
|
DBPropSet.guidPropertySet = DBPROPSET_ROWSET;
|
|
DBPropSet.cProperties = cProperties;
|
|
DBPropSet.rgProperties = rgProps;
|
|
|
|
//Set the properties for our rowset we'll test
|
|
if (SettableProperty(DBPROP_IRowsetChange, DBPROPSET_ROWSET, (IUnknown *)m_pThisTestModule->m_pIUnknown, DATASOURCE_INTERFACE) &
|
|
SettableProperty(DBPROP_UPDATABILITY, DBPROPSET_ROWSET, (IUnknown *)m_pThisTestModule->m_pIUnknown, DATASOURCE_INTERFACE))
|
|
SetRowsetProperties(&DBPropSet, 1);
|
|
|
|
hr=CreateRowsetObject(SELECT_VALIDATIONORDER);
|
|
|
|
if (SUCCEEDED(hr))
|
|
hr = VerifyRowsetProperties((IUnknown *)m_pIAccessor, &DBPropSet, 1);
|
|
|
|
if (!SUCCEEDED(hr))
|
|
{
|
|
odtLog << L"Couldn't create the rowset as requested.\n";
|
|
fSuccess = TEST_SKIPPED;
|
|
goto CLEANUP;
|
|
}
|
|
|
|
//Get rowset interface off of our main rowset object
|
|
if (!VerifyInterface(m_pIAccessor,IID_IRowset, ROWSET_INTERFACE,(IUnknown **)&m_pGetIRowset))
|
|
goto CLEANUP;
|
|
|
|
//Find out what deferred and cache deferred behavior is supported
|
|
if (!VerifyInterface(m_pIAccessor,IID_IRowsetInfo,ROWSET_INTERFACE,(IUnknown **)&pIRowsetInfo))
|
|
goto CLEANUP;
|
|
|
|
//We may get errors occured from not supported properties
|
|
m_hr = pIRowsetInfo->GetProperties(1, &PropIDSet, &cPropSets, &rgPropSets);
|
|
if (m_hr == DB_E_ERRORSOCCURRED)
|
|
{
|
|
// Neither of the properties were supported, we can't continue
|
|
|
|
//Make sure that the error we get sets the right status
|
|
//Anything other than NOTSUPPORTED is a bug. If we
|
|
//don't have support, we'll just fail and not do this variation.
|
|
COMPARE(rgPropSets[0].rgProperties[0].dwStatus, DBPROPSTATUS_NOTSUPPORTED);
|
|
odtLog << L"Required properties not supported, test case skipped.\n";
|
|
fSuccess=TEST_SKIPPED;
|
|
goto CLEANUP;
|
|
}
|
|
|
|
|
|
//Any other error is just that, an error!
|
|
if (m_hr != DB_S_ERRORSOCCURRED)
|
|
if (!CHECK(m_hr, S_OK))
|
|
goto CLEANUP;
|
|
|
|
//Set our flags so we know what is supported
|
|
if (rgPropSets[0].rgProperties[0].dwStatus == DBPROPSTATUS_OK &&
|
|
V_BOOL(&rgPropSets[0].rgProperties[0].vValue) == VARIANT_TRUE)
|
|
m_fDeferredSupported = TRUE;
|
|
else
|
|
m_fDeferredSupported = FALSE;
|
|
|
|
if (rgPropSets[0].rgProperties[1].dwStatus == DBPROPSTATUS_OK &&
|
|
V_BOOL(&rgPropSets[0].rgProperties[1].vValue) == VARIANT_TRUE)
|
|
m_fCacheSupported = TRUE;
|
|
else
|
|
m_fCacheSupported = FALSE;
|
|
|
|
//Use DB Session that we also used for current rowset object
|
|
//for our SetDataRowset
|
|
m_pSetRowset->SetDBSession(m_pThisTestModule->m_pIUnknown2);
|
|
|
|
//Have this testcase use the table created in ModuleInit, but don't
|
|
//let table be deleted, since we use it for the other rowset
|
|
m_pSetRowset->SetTable((CTable *)m_pThisTestModule->m_pVoid, DELETETABLE_NO);
|
|
|
|
//Ask for SetData on the rowset we'll use to change data
|
|
if (SettableProperty(DBPROP_IRowsetChange, DBPROPSET_ROWSET, (IUnknown *)m_pThisTestModule->m_pIUnknown, DATASOURCE_INTERFACE) &
|
|
SettableProperty(DBPROP_UPDATABILITY, DBPROPSET_ROWSET, (IUnknown *)m_pThisTestModule->m_pIUnknown, DATASOURCE_INTERFACE))
|
|
m_pSetRowset->SetRowsetProperties(&DBPropSet, 1);
|
|
|
|
//Create the new rowset and place it in m_pSetIRowset
|
|
hr=m_pSetRowset->CreateRowsetObject(SELECT_VALIDATIONORDER);
|
|
|
|
if (SUCCEEDED(hr))
|
|
hr = VerifyRowsetProperties((IUnknown *)m_pSetRowset->m_pIAccessor, &DBPropSet, 1);
|
|
|
|
if (FAILED(hr))
|
|
goto CLEANUP;
|
|
|
|
//If we've gotten this far, we know IRowset is supported, so expect it as an interface
|
|
if (!VerifyInterface(m_pSetRowset->m_pIAccessor,IID_IRowset,ROWSET_INTERFACE,(IUnknown **)&m_pSetIRowset))
|
|
goto CLEANUP;
|
|
|
|
//Get rowsetchange interface off of our SetData rowset object, if this
|
|
//isn't supported, we are done since we can't test anything without SetData
|
|
if (!VerifyInterface(m_pSetIRowset,IID_IRowsetChange,ROWSET_INTERFACE,
|
|
(IUnknown **)&m_pSetIRowsetChange))
|
|
{
|
|
//Return but don't increment error count, since we can't
|
|
//continue without IRowsetChange support
|
|
fSuccess = FALSE;
|
|
goto CLEANUP;
|
|
}
|
|
|
|
|
|
//Build a colid array based on our rowset
|
|
if (!VerifyInterface(m_pIAccessor,IID_IColumnsInfo,ROWSET_INTERFACE,(IUnknown **)&pIColInfo))
|
|
goto CLEANUP;
|
|
if (!CHECK(pIColInfo->GetColumnInfo(&cColumns, &rgColInfo, &pStr), S_OK))
|
|
goto CLEANUP;
|
|
m_rgDBIDs = (DBID *)m_pIMalloc->Alloc((cColumns) * sizeof(DBID));
|
|
while (cColumns)
|
|
{
|
|
//NOTE: The index to this array will equal the column number
|
|
//associated with that colid minus one. It is assumed there
|
|
//are no bookmarks on this rowset
|
|
cColumns --;
|
|
m_rgDBIDs[cColumns] = rgColInfo[cColumns].columnid;
|
|
}
|
|
|
|
|
|
//Get the three accessors we'll be testing with
|
|
if (!CHECK(GetAccessorAndBindings(m_pIAccessor, DBACCESSOR_ROWDATA,
|
|
&m_FixedAccessor, &m_rgFixedBindings, &m_cFixedBindings, &m_cbFixedRowSize,
|
|
DBPART_LENGTH | DBPART_STATUS | DBPART_VALUE,
|
|
FIXED_LEN_COLS_BOUND,
|
|
FORWARD, NO_COLS_BY_REF, NULL, NULL,
|
|
NULL, DBTYPE_EMPTY, 0, NULL, NULL,
|
|
NO_COLS_OWNED_BY_PROV, DBPARAMIO_NOTPARAM,
|
|
m_fBindLongCols),S_OK))
|
|
goto CLEANUP;
|
|
|
|
if (!CHECK(GetAccessorAndBindings(m_pIAccessor, DBACCESSOR_ROWDATA,
|
|
&m_VariableAccessor, &m_rgVariableBindings, &m_cVariableBindings, &m_cbVariableRowSize,
|
|
DBPART_LENGTH | DBPART_STATUS | DBPART_VALUE,
|
|
VARIABLE_LEN_COLS_BOUND,
|
|
FORWARD, NO_COLS_BY_REF, NULL, NULL,
|
|
NULL, DBTYPE_EMPTY, 0, NULL, NULL,
|
|
NO_COLS_OWNED_BY_PROV, DBPARAMIO_NOTPARAM,
|
|
m_fBindLongCols),S_OK))
|
|
goto CLEANUP;
|
|
|
|
if (!CHECK(GetAccessorAndBindings(m_pIAccessor, DBACCESSOR_ROWDATA,
|
|
&m_GetAllAccessor, &m_rgGetAllBindings, &m_cGetAllBindings, &m_cbGetAllRowSize,
|
|
DBPART_LENGTH | DBPART_STATUS | DBPART_VALUE,
|
|
ALL_COLS_BOUND,
|
|
FORWARD, NO_COLS_BY_REF, NULL, NULL,
|
|
NULL, DBTYPE_EMPTY, 0, NULL, NULL,
|
|
NO_COLS_OWNED_BY_PROV, DBPARAMIO_NOTPARAM,
|
|
m_fBindLongCols),S_OK))
|
|
goto CLEANUP;
|
|
|
|
if (!CHECK(GetAccessorAndBindings(m_pSetRowset->m_pIAccessor, DBACCESSOR_ROWDATA,
|
|
&m_SetAllAccessor, &m_rgSetAllBindings, &m_cSetAllBindings, &m_cbSetAllRowSize,
|
|
DBPART_LENGTH | DBPART_STATUS | DBPART_VALUE, UPDATEABLE_COLS_BOUND,
|
|
FORWARD, NO_COLS_BY_REF, NULL, NULL,
|
|
NULL, DBTYPE_EMPTY, 0, NULL, NULL,
|
|
NO_COLS_OWNED_BY_PROV, DBPARAMIO_NOTPARAM,
|
|
m_fBindLongCols),S_OK))
|
|
goto CLEANUP;
|
|
|
|
//If we got this far everything succeeded
|
|
fSuccess = TRUE;
|
|
}
|
|
|
|
CLEANUP:
|
|
|
|
FreeProperties(&cPropSets, &rgPropSets);
|
|
|
|
SAFE_RELEASE(pIRowsetInfo);
|
|
SAFE_RELEASE(pIColInfo);
|
|
PROVIDER_FREE(rgColInfo);
|
|
PROVIDER_FREE(pStr);
|
|
|
|
return fSuccess;
|
|
}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(1)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc Deferred on, CacheDeferred off - All Columns
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCDeferredColumns::Variation_1()
|
|
{
|
|
BOOL fSuccess = FALSE;
|
|
HROW rghRow[1] = {NULL};
|
|
HROW * phRow = &rghRow[0];
|
|
DBCOUNTITEM cRowsObtained = 0;
|
|
BYTE * pGetData1 = NULL;
|
|
BYTE * pGetData2 = NULL;
|
|
|
|
//Skip this variation if the right properties are not supported
|
|
if (!m_fDeferredSupported)
|
|
{
|
|
odtLog << wszDeferredNotSupported;
|
|
return TEST_PASS;
|
|
}
|
|
|
|
//Make sure we start with Primary data for our one row table
|
|
if (!CHECK(SetData(PRIMARY), S_OK))
|
|
goto CLEANUP;
|
|
|
|
//Set up the properties for this variation: deferred on, cachedeferred off
|
|
if (!CHECK(SetDeferredProperties(TRUE, FALSE, 0, NULL), S_OK))
|
|
goto CLEANUP;
|
|
|
|
if (!CHECK(m_pGetIRowset->GetNextRows(NULL, 0, 1, &cRowsObtained, &phRow),S_OK))
|
|
goto CLEANUP;
|
|
COMPARE(cRowsObtained, 1);
|
|
|
|
//Now get some of the columns with one call, some with the next call to GetData
|
|
pGetData1 = (BYTE *)m_pIMalloc->Alloc(m_cbVariableRowSize);
|
|
if (!pGetData1)
|
|
goto CLEANUP;
|
|
if (!CHECK(m_pGetIRowset->GetData(rghRow[0], m_VariableAccessor, pGetData1), S_OK))
|
|
goto CLEANUP;
|
|
|
|
pGetData2 = (BYTE *)m_pIMalloc->Alloc(m_cbFixedRowSize);
|
|
if (!pGetData2)
|
|
goto CLEANUP;
|
|
if (!CHECK(m_pGetIRowset->GetData(rghRow[0], m_FixedAccessor, pGetData2), S_OK))
|
|
goto CLEANUP;
|
|
|
|
if (!CompareData(m_cRowsetCols, m_rgTableColOrds, g_uiRowNum, pGetData1, m_cVariableBindings,
|
|
m_rgVariableBindings, m_pTable, m_pIMalloc, PRIMARY))
|
|
goto CLEANUP;
|
|
|
|
if (!CompareData(m_cRowsetCols, m_rgTableColOrds, g_uiRowNum, pGetData2, m_cFixedBindings,
|
|
m_rgFixedBindings, m_pTable, m_pIMalloc, PRIMARY))
|
|
goto CLEANUP;
|
|
|
|
//We got this far, so we have succeeded
|
|
fSuccess = TRUE;
|
|
|
|
|
|
CLEANUP:
|
|
if (rghRow[0])
|
|
CHECK(m_pGetIRowset->ReleaseRows(1, rghRow, NULL, NULL, NULL),S_OK);
|
|
PROVIDER_FREE(pGetData1);
|
|
PROVIDER_FREE(pGetData2);
|
|
|
|
if (fSuccess)
|
|
return TEST_PASS;
|
|
else
|
|
return TEST_FAIL;
|
|
}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(2)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc Deferred on, CacheDeferred on - Fixed Columns
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCDeferredColumns::Variation_2()
|
|
{
|
|
BOOL fSuccess = FALSE;
|
|
HROW rghRow[1] = {NULL};
|
|
HROW * phRow = &rghRow[0];
|
|
DBCOUNTITEM cRowsObtained = 0;
|
|
BYTE * pGetData1 = NULL;
|
|
|
|
//Skip this variation if the right properties are not supported
|
|
if (!m_fDeferredSupported)
|
|
{
|
|
odtLog << wszDeferredNotSupported;
|
|
return TEST_SKIPPED;
|
|
}
|
|
if (!m_fCacheSupported)
|
|
{
|
|
odtLog << wszCacheDeferredNotSupported;
|
|
return TEST_SKIPPED;
|
|
}
|
|
|
|
//Make sure we start with Primary data for our one row table
|
|
if (!CHECK(SetData(PRIMARY), S_OK))
|
|
goto CLEANUP;
|
|
|
|
//Set up the properties for this variation: deferred on, cachedeferred off
|
|
if (!CHECK(SetDeferredProperties(TRUE, TRUE, m_cFixedBindings,
|
|
m_rgFixedBindings), S_OK))
|
|
goto CLEANUP;
|
|
|
|
if (!CHECK(m_pGetIRowset->GetNextRows(NULL, 0, 1, &cRowsObtained, &phRow),S_OK))
|
|
goto CLEANUP;
|
|
COMPARE(cRowsObtained, 1);
|
|
|
|
//Now get all of the columns, so the deferred ones are cached
|
|
pGetData1 = (BYTE *)m_pIMalloc->Alloc(m_cbGetAllRowSize);
|
|
if (!pGetData1)
|
|
goto CLEANUP;
|
|
if (!CHECK(m_pGetIRowset->GetData(rghRow[0], m_GetAllAccessor, pGetData1), S_OK))
|
|
goto CLEANUP;
|
|
|
|
//Now change the data while the first rowset is open
|
|
if (!CHECK(SetData(SECONDARY), S_OK))
|
|
goto CLEANUP;
|
|
|
|
//Release the row and refetch to make sure we have to reaccess the cached values
|
|
if (!CHECK(m_pGetIRowset->ReleaseRows(1, rghRow, NULL, NULL, NULL), S_OK))
|
|
goto CLEANUP;
|
|
rghRow[0] = DB_NULL_HROW;
|
|
//Could get DB_S_COMMANDREEXECUTED here
|
|
if (FAILED(m_pGetIRowset->RestartPosition(NULL)))
|
|
goto CLEANUP;
|
|
if (!CHECK(m_pGetIRowset->GetNextRows(NULL, 0, 1, &cRowsObtained, &phRow),S_OK))
|
|
goto CLEANUP;
|
|
COMPARE(cRowsObtained, 1);
|
|
|
|
//Now Get the data and make sure it is using the cached, not the new values
|
|
if (!CHECK(m_pGetIRowset->GetData(rghRow[0], m_FixedAccessor, pGetData1), S_OK))
|
|
goto CLEANUP;
|
|
|
|
if (!CompareData(m_cRowsetCols, m_rgTableColOrds, g_uiRowNum, pGetData1, m_cFixedBindings,
|
|
m_rgFixedBindings, m_pTable, m_pIMalloc, PRIMARY))
|
|
goto CLEANUP;
|
|
|
|
//We got this far, so we have succeeded
|
|
fSuccess = TRUE;
|
|
|
|
CLEANUP:
|
|
if (rghRow[0])
|
|
CHECK(m_pGetIRowset->ReleaseRows(1, rghRow, NULL, NULL, NULL),S_OK);
|
|
PROVIDER_FREE(pGetData1);
|
|
|
|
if (fSuccess)
|
|
return TEST_PASS;
|
|
else
|
|
return TEST_FAIL;
|
|
}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(3)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc Deferred on, CacheDeferred on - Variable Columns
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCDeferredColumns::Variation_3()
|
|
{
|
|
BOOL fSuccess = FALSE;
|
|
HROW rghRow[1] = {NULL};
|
|
HROW * phRow = &rghRow[0];
|
|
DBCOUNTITEM cRowsObtained = 0;
|
|
BYTE * pGetData1 = NULL;
|
|
|
|
//Skip this variation if the right properties are not supported
|
|
if (!m_fDeferredSupported)
|
|
{
|
|
odtLog << wszDeferredNotSupported;
|
|
return TEST_SKIPPED;
|
|
}
|
|
if (!m_fCacheSupported)
|
|
{
|
|
odtLog << wszCacheDeferredNotSupported;
|
|
return TEST_SKIPPED;
|
|
}
|
|
//Make sure we start with Primary data for our one row table
|
|
if (!CHECK(SetData(PRIMARY), S_OK))
|
|
goto CLEANUP;
|
|
|
|
//Set up the properties for this variation: deferred on, cachedeferred on
|
|
if (!CHECK(SetDeferredProperties(TRUE, TRUE, m_cVariableBindings,
|
|
m_rgVariableBindings), S_OK))
|
|
goto CLEANUP;
|
|
|
|
if (!CHECK(m_pGetIRowset->GetNextRows(NULL, 0, 1, &cRowsObtained, &phRow),S_OK))
|
|
goto CLEANUP;
|
|
COMPARE(cRowsObtained, 1);
|
|
|
|
//Now get all of the columns, so the deferred ones are cached
|
|
pGetData1 = (BYTE *)m_pIMalloc->Alloc(m_cbGetAllRowSize);
|
|
if (!pGetData1)
|
|
goto CLEANUP;
|
|
if (!CHECK(m_pGetIRowset->GetData(rghRow[0], m_GetAllAccessor, pGetData1), S_OK))
|
|
goto CLEANUP;
|
|
|
|
//Now change the data while the first rowset is open
|
|
if (!CHECK(SetData(SECONDARY), S_OK))
|
|
goto CLEANUP;
|
|
|
|
//Release the row and refetch to make sure we have to reaccess the cached values
|
|
if (!CHECK(m_pGetIRowset->ReleaseRows(1, rghRow, NULL, NULL, NULL), S_OK))
|
|
goto CLEANUP;
|
|
rghRow[0] = DB_NULL_HROW;
|
|
//Could get DB_S_COMMANDREEXECUTED here
|
|
if (FAILED(m_pGetIRowset->RestartPosition(NULL)))
|
|
goto CLEANUP;
|
|
if (!CHECK(m_pGetIRowset->GetNextRows(NULL, 0, 1, &cRowsObtained, &phRow),S_OK))
|
|
goto CLEANUP;
|
|
COMPARE(cRowsObtained, 1);
|
|
|
|
|
|
//Now Get the data and make sure it is using the cached, not the new values
|
|
if (!CHECK(m_pGetIRowset->GetData(rghRow[0], m_VariableAccessor, pGetData1), S_OK))
|
|
goto CLEANUP;
|
|
|
|
if (!CompareData(m_cRowsetCols, m_rgTableColOrds, g_uiRowNum, pGetData1, m_cVariableBindings,
|
|
m_rgVariableBindings, m_pTable, m_pIMalloc, PRIMARY))
|
|
goto CLEANUP;
|
|
|
|
//We got this far, so we have succeeded
|
|
fSuccess = TRUE;
|
|
|
|
CLEANUP:
|
|
if (rghRow[0])
|
|
CHECK(m_pGetIRowset->ReleaseRows(1, rghRow, NULL, NULL, NULL),S_OK);
|
|
PROVIDER_FREE(pGetData1);
|
|
|
|
if (fSuccess)
|
|
return TEST_PASS;
|
|
else
|
|
return TEST_FAIL;
|
|
|
|
}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(4)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc Deferred on, CacheDeferred on - All Columns
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCDeferredColumns::Variation_4()
|
|
{
|
|
BOOL fSuccess = FALSE;
|
|
HROW rghRow[1] = {NULL};
|
|
HROW * phRow = &rghRow[0];
|
|
DBCOUNTITEM cRowsObtained = 0;
|
|
BYTE * pGetData1 = NULL;
|
|
|
|
//Skip this variation if the right properties are not supported
|
|
if (!m_fDeferredSupported)
|
|
{
|
|
odtLog << wszDeferredNotSupported;
|
|
return TEST_SKIPPED;
|
|
}
|
|
if (!m_fCacheSupported)
|
|
{
|
|
odtLog << wszCacheDeferredNotSupported;
|
|
return TEST_SKIPPED;
|
|
}
|
|
//Make sure we start with Primary data for our one row table
|
|
if (!CHECK(SetData(PRIMARY), S_OK))
|
|
goto CLEANUP;
|
|
|
|
//Set up the properties for this variation: deferred on, cachedeferred on
|
|
if (!CHECK(SetDeferredProperties(TRUE, TRUE, m_cGetAllBindings,
|
|
m_rgGetAllBindings), S_OK))
|
|
goto CLEANUP;
|
|
|
|
if (!CHECK(m_pGetIRowset->GetNextRows(NULL, 0, 1, &cRowsObtained, &phRow),S_OK))
|
|
goto CLEANUP;
|
|
COMPARE(cRowsObtained, 1);
|
|
|
|
//Now get all of the columns, so the deferred ones are cached
|
|
pGetData1 = (BYTE *)m_pIMalloc->Alloc(m_cbGetAllRowSize);
|
|
if (!pGetData1)
|
|
goto CLEANUP;
|
|
if (!CHECK(m_pGetIRowset->GetData(rghRow[0], m_GetAllAccessor, pGetData1), S_OK))
|
|
goto CLEANUP;
|
|
|
|
//Now change the data while the first rowset is open
|
|
if (!CHECK(SetData(SECONDARY), S_OK))
|
|
goto CLEANUP;
|
|
|
|
//Release the row and refetch to make sure we have to reaccess the cached values
|
|
if (!CHECK(m_pGetIRowset->ReleaseRows(1, rghRow, NULL, NULL, NULL), S_OK))
|
|
goto CLEANUP;
|
|
rghRow[0] = DB_NULL_HROW;
|
|
//Could get DB_S_COMMANDREEXECUTED here
|
|
if (FAILED(m_pGetIRowset->RestartPosition(NULL)))
|
|
goto CLEANUP;
|
|
if (!CHECK(m_pGetIRowset->GetNextRows(NULL, 0, 1, &cRowsObtained, &phRow),S_OK))
|
|
goto CLEANUP;
|
|
COMPARE(cRowsObtained, 1);
|
|
|
|
//Now Get the data and make sure it is using the cached, not the new values
|
|
if (!CHECK(m_pGetIRowset->GetData(rghRow[0], m_GetAllAccessor, pGetData1), S_OK))
|
|
goto CLEANUP;
|
|
|
|
if (!CompareData(m_cRowsetCols, m_rgTableColOrds, g_uiRowNum, pGetData1, m_cGetAllBindings,
|
|
m_rgGetAllBindings, m_pTable, m_pIMalloc, PRIMARY))
|
|
goto CLEANUP;
|
|
|
|
//We got this far, so we have succeeded
|
|
fSuccess = TRUE;
|
|
|
|
CLEANUP:
|
|
if (rghRow[0])
|
|
CHECK(m_pGetIRowset->ReleaseRows(1, rghRow, NULL, NULL, NULL),S_OK);
|
|
PROVIDER_FREE(pGetData1);
|
|
|
|
if (fSuccess)
|
|
return TEST_PASS;
|
|
else
|
|
return TEST_FAIL;
|
|
|
|
|
|
}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(5)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc Deferred off, CacheDeferred on - All Columns
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCDeferredColumns::Variation_5()
|
|
{
|
|
BOOL fSuccess = FALSE;
|
|
HROW rghRow[1] = {NULL};
|
|
HROW * phRow = &rghRow[0];
|
|
DBCOUNTITEM cRowsObtained = 0;
|
|
BYTE * pGetData1 = NULL;
|
|
|
|
//Skip this variation if the right properties are not supported
|
|
if (m_fDeferredSupported)
|
|
{
|
|
odtLog << wszDeferredSupported;
|
|
return TEST_SKIPPED;
|
|
}
|
|
if (!m_fCacheSupported)
|
|
{
|
|
odtLog << wszCacheDeferredNotSupported;
|
|
return TEST_SKIPPED;
|
|
}
|
|
//Make sure we start with Primary data for our one row table
|
|
if (!CHECK(SetData(PRIMARY), S_OK))
|
|
goto CLEANUP;
|
|
|
|
//Set up the properties for this variation: deferred off, cachedeferred on
|
|
//This should be identical to deferred on, since cachedeferred implies deferred.
|
|
if (!CHECK(SetDeferredProperties(FALSE, TRUE, m_cGetAllBindings,
|
|
m_rgGetAllBindings), S_OK))
|
|
goto CLEANUP;
|
|
|
|
if (!CHECK(m_pGetIRowset->GetNextRows(NULL, 0, 1, &cRowsObtained, &phRow),S_OK))
|
|
goto CLEANUP;
|
|
COMPARE(cRowsObtained, 1);
|
|
|
|
//Now get all of the columns, so the deferred ones are cached
|
|
pGetData1 = (BYTE *)m_pIMalloc->Alloc(m_cbGetAllRowSize);
|
|
if (!pGetData1)
|
|
goto CLEANUP;
|
|
if (!CHECK(m_pGetIRowset->GetData(rghRow[0], m_GetAllAccessor, pGetData1), S_OK))
|
|
goto CLEANUP;
|
|
|
|
//Now change the data while the first rowset is open
|
|
if (!CHECK(SetData(SECONDARY), S_OK))
|
|
goto CLEANUP;
|
|
|
|
//Release the row and refetch to make sure we have to reaccess the cached values
|
|
if (!CHECK(m_pGetIRowset->ReleaseRows(1, rghRow, NULL, NULL, NULL), S_OK))
|
|
goto CLEANUP;
|
|
rghRow[0] = DB_NULL_HROW;
|
|
//Could get DB_S_COMMANDREEXECUTED here
|
|
if (FAILED(m_pGetIRowset->RestartPosition(NULL)))
|
|
goto CLEANUP;
|
|
if (!CHECK(m_pGetIRowset->GetNextRows(NULL, 0, 1, &cRowsObtained, &phRow),S_OK))
|
|
goto CLEANUP;
|
|
COMPARE(cRowsObtained, 1);
|
|
|
|
//Now Get the data and make sure it is using the cached, not the new values
|
|
if (!CHECK(m_pGetIRowset->GetData(rghRow[0], m_GetAllAccessor, pGetData1), S_OK))
|
|
goto CLEANUP;
|
|
|
|
if (!CompareData(m_cRowsetCols, m_rgTableColOrds, g_uiRowNum, pGetData1, m_cGetAllBindings,
|
|
m_rgGetAllBindings, m_pTable, m_pIMalloc, PRIMARY))
|
|
goto CLEANUP;
|
|
|
|
//We got this far, so we have succeeded
|
|
fSuccess = TRUE;
|
|
|
|
CLEANUP:
|
|
if (rghRow[0])
|
|
CHECK(m_pGetIRowset->ReleaseRows(1, rghRow, NULL, NULL, NULL),S_OK);
|
|
PROVIDER_FREE(pGetData1);
|
|
|
|
if (fSuccess)
|
|
return TEST_PASS;
|
|
else
|
|
return TEST_FAIL;
|
|
|
|
|
|
}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_TERMINATE_METHOD
|
|
//--------------------------------------------------------------------
|
|
// @mfunc TestCase Termination Routine
|
|
//
|
|
// @rdesc TRUE or FALSE
|
|
//
|
|
BOOL TCDeferredColumns::Terminate()
|
|
{
|
|
|
|
//Release accessors
|
|
if (m_FixedAccessor)
|
|
{
|
|
m_pIAccessor->ReleaseAccessor(m_FixedAccessor, NULL);
|
|
m_FixedAccessor = DB_NULL_HACCESSOR;
|
|
}
|
|
if (m_VariableAccessor)
|
|
{
|
|
m_pIAccessor->ReleaseAccessor(m_VariableAccessor, NULL);
|
|
m_VariableAccessor = DB_NULL_HACCESSOR;
|
|
}
|
|
|
|
|
|
if (m_GetAllAccessor != DB_NULL_HACCESSOR)
|
|
{
|
|
m_pIAccessor->ReleaseAccessor(m_GetAllAccessor, NULL);
|
|
m_GetAllAccessor = DB_NULL_HACCESSOR;
|
|
}
|
|
|
|
if (m_SetAllAccessor != DB_NULL_HACCESSOR)
|
|
{
|
|
m_pSetRowset->m_pIAccessor->ReleaseAccessor(m_SetAllAccessor, NULL);
|
|
m_SetAllAccessor = DB_NULL_HACCESSOR;
|
|
}
|
|
|
|
//Release memory associated with binding arrays
|
|
PROVIDER_FREE(m_rgFixedBindings);
|
|
PROVIDER_FREE(m_rgVariableBindings);
|
|
PROVIDER_FREE(m_rgGetAllBindings);
|
|
PROVIDER_FREE(m_rgSetAllBindings);
|
|
|
|
SAFE_RELEASE(m_pGetIRowset);
|
|
SAFE_RELEASE(m_pSetIRowset);
|
|
SAFE_RELEASE(m_pSetIRowsetChange);
|
|
|
|
//We don't need the whole CRowset object anymore, we have an interface to the rowset
|
|
if (m_pSetRowset)
|
|
{
|
|
m_pSetRowset->ReleaseRowsetObject();
|
|
m_pSetRowset->ReleaseCommandObject();
|
|
m_pSetRowset->ReleaseDBSession();
|
|
delete m_pSetRowset;
|
|
}
|
|
|
|
PROVIDER_FREE(m_rgDBIDs);
|
|
|
|
ReleaseRowsetObject();
|
|
|
|
// {{ TCW_TERM_BASECLASS_CHECK2
|
|
return(CAccessor::Terminate());
|
|
} // }}
|
|
// }}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_TC_PROTOTYPE(TCCommandAccessorTransactions)
|
|
//*-----------------------------------------------------------------------
|
|
//| Test Case: TCCommandAccessorTransactions - Commit/Abort behavior for Command Accessors
|
|
//| Created: 12/18/95
|
|
//*-----------------------------------------------------------------------
|
|
|
|
//--------------------------------------------------------------------
|
|
// @mfunc TestCase Initialization Routine
|
|
//
|
|
// @rdesc TRUE or FALSE
|
|
//
|
|
BOOL TCCommandAccessorTransactions::Init()
|
|
{
|
|
//if command is not supported, skip this test
|
|
if(!g_fCmdSupported)
|
|
{
|
|
odtLog << wszCommandNotSupported;
|
|
return TEST_SKIPPED;
|
|
}
|
|
|
|
// {{ TCW_INIT_BASECLASS_CHECK
|
|
if(CTransaction::Init())
|
|
// }}
|
|
{
|
|
|
|
//Set up a simple binding to use
|
|
m_cBindings = 1;
|
|
m_rgBindings[0].dwPart = DBPART_VALUE;
|
|
m_rgBindings[0].eParamIO = DBPARAMIO_INPUT;
|
|
m_rgBindings[0].iOrdinal = 1;
|
|
m_rgBindings[0].dwFlags = 0;
|
|
m_rgBindings[0].wType = DBTYPE_STR;
|
|
m_rgBindings[0].pTypeInfo = NULL;
|
|
m_rgBindings[0].pObject = NULL;
|
|
m_rgBindings[0].dwMemOwner = DBMEMOWNER_CLIENTOWNED;
|
|
m_rgBindings[0].bPrecision = 0;
|
|
m_rgBindings[0].bScale = 0;
|
|
m_rgBindings[0].pBindExt = NULL;
|
|
m_rgBindings[0].obValue = 0;
|
|
m_rgBindings[0].cbMaxLen = MAX_COL_SIZE;
|
|
m_rgBindings[0].obLength = 0;
|
|
m_rgBindings[0].obStatus = 0;
|
|
|
|
//This is a mandatory interface, it should always succeed
|
|
return COMPARE(RegisterInterface(COMMAND_INTERFACE, IID_IAccessor, 0, NULL), TRUE);
|
|
|
|
}
|
|
return TEST_SKIPPED;
|
|
}
|
|
|
|
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc TestTxn
|
|
// Tests commit/abort with respect to IAccessor on commands
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCCommandAccessorTransactions::TestTxn(ETXN eTxn, BOOL fRetaining)
|
|
{
|
|
|
|
BOOL fSuccess = FALSE;
|
|
HACCESSOR hAccessor = DB_NULL_HACCESSOR;
|
|
IAccessor * pCmdIAccessor = NULL;
|
|
|
|
|
|
if (!StartTransaction(SELECT_VALIDATIONORDER, (IUnknown **)&pCmdIAccessor,
|
|
0, NULL, NULL, ISOLATIONLEVEL_READUNCOMMITTED))
|
|
goto CLEANUP;
|
|
|
|
if (eTxn == ETXN_COMMIT)
|
|
{
|
|
//Commit the transaction, with retention as specified
|
|
if(!GetCommit(fRetaining))
|
|
goto CLEANUP;
|
|
}
|
|
else
|
|
{
|
|
//Abort the transaction, with retention as specified
|
|
if(!GetAbort(fRetaining))
|
|
goto CLEANUP;
|
|
}
|
|
|
|
//Make sure everything still works after commit or abort
|
|
if (CHECK(pCmdIAccessor->CreateAccessor(DBACCESSOR_ROWDATA, 1,
|
|
m_rgBindings, m_cbRowSize, &hAccessor, NULL), S_OK))
|
|
{
|
|
if (CHECK(pCmdIAccessor->GetBindings(hAccessor, &m_dwFlags,
|
|
&m_cBindings, &m_rgGetBindings), S_OK))
|
|
{
|
|
PROVIDER_FREE(m_rgGetBindings);
|
|
fSuccess = CHECK(pCmdIAccessor->ReleaseAccessor(hAccessor, NULL), S_OK);
|
|
hAccessor = DB_NULL_HACCESSOR;
|
|
}
|
|
}
|
|
|
|
CLEANUP:
|
|
|
|
if (pCmdIAccessor)
|
|
{
|
|
if (hAccessor != DB_NULL_HACCESSOR)
|
|
CHECK(pCmdIAccessor->ReleaseAccessor(hAccessor, NULL), S_OK);
|
|
|
|
SAFE_RELEASE(pCmdIAccessor);
|
|
}
|
|
|
|
//Return code of Commit/Abort will vary depending on whether
|
|
//or not we have an open txn, so adjust accordingly
|
|
if (fRetaining)
|
|
CleanUpTransaction(S_OK);
|
|
else
|
|
CleanUpTransaction(XACT_E_NOTRANSACTION);
|
|
|
|
if (fSuccess)
|
|
return TEST_PASS;
|
|
else
|
|
return TEST_FAIL;
|
|
|
|
}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(1)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc Commit Retaining
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCCommandAccessorTransactions::Variation_1()
|
|
{
|
|
return TestTxn(ETXN_COMMIT, TRUE);
|
|
}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(2)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc Commit Non Retaining
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCCommandAccessorTransactions::Variation_2()
|
|
{
|
|
return TestTxn(ETXN_COMMIT, FALSE);
|
|
}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(3)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc Abort Retaining
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCCommandAccessorTransactions::Variation_3()
|
|
{
|
|
return TestTxn(ETXN_ABORT, TRUE);
|
|
}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(4)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc Abort Non Retaining
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCCommandAccessorTransactions::Variation_4()
|
|
{
|
|
return TestTxn(ETXN_ABORT, FALSE);
|
|
}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_TERMINATE_METHOD
|
|
//--------------------------------------------------------------------
|
|
// @mfunc TestCase Termination Routine
|
|
//
|
|
// @rdesc TRUE or FALSE
|
|
//
|
|
BOOL TCCommandAccessorTransactions::Terminate()
|
|
{
|
|
// {{ TCW_TERM_BASECLASS_CHECK2
|
|
return(CTransaction::Terminate());
|
|
} // }}
|
|
// }}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_TC_PROTOTYPE(TCRowsetAccessorTransactions)
|
|
//*-----------------------------------------------------------------------
|
|
//| Test Case: TCRowsetAccessorTransactions - Commit/Abort behavior for Rowset Accessors
|
|
//| Created: 12/18/95
|
|
//*-----------------------------------------------------------------------
|
|
|
|
//--------------------------------------------------------------------
|
|
// @mfunc TestCase Initialization Routine
|
|
//
|
|
// @rdesc TRUE or FALSE
|
|
//
|
|
BOOL TCRowsetAccessorTransactions::Init()
|
|
{
|
|
//if command is not supported, skip this test
|
|
if(!g_fCmdSupported)
|
|
{
|
|
odtLog << wszCommandNotSupported;
|
|
return TEST_SKIPPED;
|
|
}
|
|
|
|
// {{ TCW_INIT_BASECLASS_CHECK
|
|
if(CTransaction::Init())
|
|
// }}
|
|
{
|
|
//Set up a simple binding to use
|
|
m_cBindings = 1;
|
|
m_rgBindings[0].dwPart = DBPART_VALUE;
|
|
m_rgBindings[0].eParamIO = DBPARAMIO_NOTPARAM;
|
|
m_rgBindings[0].iOrdinal = 1;
|
|
m_rgBindings[0].dwFlags = 0;
|
|
m_rgBindings[0].wType = DBTYPE_STR;
|
|
m_rgBindings[0].pTypeInfo = NULL;
|
|
m_rgBindings[0].pObject = NULL;
|
|
m_rgBindings[0].dwMemOwner = DBMEMOWNER_CLIENTOWNED;
|
|
m_rgBindings[0].bPrecision = 0;
|
|
m_rgBindings[0].bScale = 0;
|
|
m_rgBindings[0].pBindExt = NULL;
|
|
m_rgBindings[0].obValue = 0;
|
|
m_rgBindings[0].cbMaxLen = MAX_COL_SIZE;
|
|
m_rgBindings[0].obLength = 0;
|
|
m_rgBindings[0].obStatus = 0;
|
|
|
|
//This is a mandatory interface, it should always succeed
|
|
return COMPARE(RegisterInterface(ROWSET_INTERFACE, IID_IAccessor, 0, NULL), TRUE);
|
|
}
|
|
return TEST_SKIPPED;
|
|
}
|
|
|
|
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc TestTxn
|
|
// Tests commit/abort preservation with respect to IAccessor on rowsets
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCRowsetAccessorTransactions::TestTxn(ETXN eTxn, BOOL fRetaining)
|
|
{
|
|
|
|
BOOL fSuccess = FALSE;
|
|
HACCESSOR hAccessor1 = DB_NULL_HACCESSOR;
|
|
HACCESSOR hAccessor2 = DB_NULL_HACCESSOR;
|
|
IAccessor * pIAccessor = NULL;
|
|
|
|
|
|
if (!StartTransaction(SELECT_VALIDATIONORDER, (IUnknown **)&pIAccessor,
|
|
0, NULL, NULL, ISOLATIONLEVEL_READUNCOMMITTED))
|
|
goto CLEANUP;
|
|
|
|
//Get an accessor which we can try to release when zombied
|
|
if (!CHECK(pIAccessor->CreateAccessor(DBACCESSOR_ROWDATA, 1,
|
|
m_rgBindings, m_cbRowSize, &hAccessor1, NULL), S_OK))
|
|
goto CLEANUP;
|
|
|
|
if (eTxn == ETXN_COMMIT)
|
|
{
|
|
//Commit the transaction, with retention as specified
|
|
if(!GetCommit(fRetaining))
|
|
goto CLEANUP;
|
|
}
|
|
else
|
|
{
|
|
//Abort the transaction, with retention as specified
|
|
if(!GetAbort(fRetaining))
|
|
goto CLEANUP;
|
|
}
|
|
|
|
|
|
//Make sure everything still works after commit or abort
|
|
if((eTxn == ETXN_COMMIT && m_fCommitPreserve) ||
|
|
(eTxn == ETXN_ABORT && m_fAbortPreserve))
|
|
{
|
|
if (CHECK(pIAccessor->CreateAccessor(DBACCESSOR_ROWDATA, 1,
|
|
m_rgBindings, m_cbRowSize, &hAccessor2, NULL), S_OK))
|
|
{
|
|
if (CHECK(pIAccessor->GetBindings(hAccessor2, &m_dwFlags,
|
|
&m_cBindings, &m_rgGetBindings), S_OK))
|
|
{
|
|
PROVIDER_FREE(m_rgGetBindings);
|
|
fSuccess = CHECK(pIAccessor->ReleaseAccessor(hAccessor2, NULL), S_OK);
|
|
hAccessor2 = DB_NULL_HACCESSOR;
|
|
}
|
|
}
|
|
|
|
}
|
|
//Make sure we are zomibified, and can do nothing but release accessor
|
|
else
|
|
{
|
|
if (CHECK(pIAccessor->CreateAccessor(DBACCESSOR_ROWDATA, 1,
|
|
m_rgBindings, m_cbRowSize, &hAccessor2, NULL), E_UNEXPECTED))
|
|
{
|
|
if (CHECK(pIAccessor->GetBindings(hAccessor2, &m_dwFlags,
|
|
&m_cBindings, &m_rgGetBindings), E_UNEXPECTED))
|
|
{
|
|
PROVIDER_FREE(m_rgGetBindings);
|
|
//Should still be able to release accessors gotten before zombie
|
|
fSuccess = CHECK(pIAccessor->ReleaseAccessor(hAccessor1, NULL), S_OK);
|
|
hAccessor1 = DB_NULL_HACCESSOR;
|
|
}
|
|
}
|
|
|
|
}
|
|
CLEANUP:
|
|
|
|
if (pIAccessor)
|
|
{
|
|
if (hAccessor1 != DB_NULL_HACCESSOR)
|
|
CHECK(pIAccessor->ReleaseAccessor(hAccessor1, NULL), S_OK);
|
|
|
|
if (hAccessor2 != DB_NULL_HACCESSOR)
|
|
CHECK(pIAccessor->ReleaseAccessor(hAccessor2, NULL), S_OK);
|
|
|
|
SAFE_RELEASE(pIAccessor);
|
|
}
|
|
|
|
//Return code of Commit/Abort will vary depending on whether
|
|
//or not we have an open txn, so adjust accordingly
|
|
if (fRetaining)
|
|
CleanUpTransaction(S_OK);
|
|
else
|
|
CleanUpTransaction(XACT_E_NOTRANSACTION);
|
|
|
|
if (fSuccess)
|
|
return TEST_PASS;
|
|
else
|
|
return TEST_FAIL;
|
|
|
|
}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(1)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc Commit Retaining
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCRowsetAccessorTransactions::Variation_1()
|
|
{
|
|
return TestTxn(ETXN_COMMIT, TRUE);
|
|
}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(2)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc Commit Non Retaining
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCRowsetAccessorTransactions::Variation_2()
|
|
{
|
|
return TestTxn(ETXN_COMMIT, FALSE);
|
|
}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(3)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc Abort Retaining
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCRowsetAccessorTransactions::Variation_3()
|
|
{
|
|
return TestTxn(ETXN_ABORT, TRUE);
|
|
}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(4)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc Abort Non Retaining
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCRowsetAccessorTransactions::Variation_4()
|
|
{
|
|
return TestTxn(ETXN_ABORT, FALSE);
|
|
|
|
}
|
|
// }}
|
|
// {{ TCW_TERMINATE_METHOD
|
|
//--------------------------------------------------------------------
|
|
// @mfunc TestCase Termination Routine
|
|
//
|
|
// @rdesc TRUE or FALSE
|
|
//
|
|
BOOL TCRowsetAccessorTransactions::Terminate()
|
|
{
|
|
// {{ TCW_TERM_BASECLASS_CHECK2
|
|
return(CTransaction::Terminate());
|
|
} // }}
|
|
// }}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_TC_PROTOTYPE(TCExtendedErrors)
|
|
//*-----------------------------------------------------------------------
|
|
//| Test Case: TCExtendedErrors - Extended Errors
|
|
//| Created: 03/09/96
|
|
//*-----------------------------------------------------------------------
|
|
|
|
//--------------------------------------------------------------------
|
|
// @mfunc TestCase Initialization Routine
|
|
//
|
|
// @rdesc TRUE or FALSE
|
|
//
|
|
BOOL TCExtendedErrors::Init()
|
|
{
|
|
HRESULT hr;
|
|
|
|
// {{ TCW_INIT_BASECLASS_CHECK
|
|
if(CAccessor::Init())
|
|
// }}
|
|
{
|
|
//Set m_pIAccessor on a 'select *' rowset We'll
|
|
//use this interface ptr to do our tests.
|
|
hr=CreateRowsetObject(SELECT_VALIDATIONORDER);
|
|
|
|
if (CHECK(hr,S_OK))
|
|
{
|
|
|
|
//Get IAccesor on Command
|
|
//if (VerifyInterface(m_pICommand,IID_IAccessor,COMMAND_INTERFACE,
|
|
// (IUnknown **)&m_pCmdIAccessor))
|
|
//{
|
|
//Create an accessor just to build our bindings
|
|
if (CHECK(GetAccessorAndBindings(m_pIAccessor, DBACCESSOR_ROWDATA,
|
|
//if (CHECK(GetAccessorAndBindings(m_pCmdIAccessor, DBACCESSOR_ROWDATA,
|
|
&m_hAccessor, &m_rgBindings, &m_cBindings, &m_cbRowSize,
|
|
DBPART_VALUE | DBPART_LENGTH | DBPART_STATUS,
|
|
ALL_COLS_BOUND,
|
|
FORWARD, NO_COLS_BY_REF, NULL, NULL,
|
|
NULL, DBTYPE_EMPTY, 0, NULL, NULL,
|
|
NO_COLS_OWNED_BY_PROV, DBPARAMIO_NOTPARAM,
|
|
m_fBindLongCols),S_OK))
|
|
{
|
|
|
|
//Now release the accessor as we don't need it
|
|
CHECK(m_pIAccessor->ReleaseAccessor(m_hAccessor, NULL), S_OK);
|
|
//CHECK(m_pCmdIAccessor->ReleaseAccessor(m_hAccessor, NULL), S_OK);
|
|
m_hAccessor = DB_NULL_HACCESSOR;
|
|
return TRUE;
|
|
}
|
|
//}
|
|
}
|
|
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(1)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc Valid IAccessor calls with previous error object existing.
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCExtendedErrors::Variation_1()
|
|
{
|
|
|
|
BOOL fResults = FALSE;
|
|
DBACCESSORFLAGS dwFlags = 0;
|
|
|
|
//For each method of the interface, first create an error object on
|
|
//the current thread, then try get S_OK from the IAccessor method.
|
|
//We then check extended errors to verify nothing is set since an
|
|
//error object shouldn't exist following a successful call.
|
|
|
|
m_pExtError->CauseError();
|
|
if (CHECK(m_hr = m_pIAccessor->CreateAccessor(DBACCESSOR_ROWDATA, m_cBindings,
|
|
m_rgBindings, 0, &m_hAccessor, NULL), S_OK))
|
|
{
|
|
//Do extended check following CreateAccessor
|
|
fResults = XCHECK(m_pIAccessor, IID_IAccessor, m_hr);
|
|
|
|
m_pExtError->CauseError();
|
|
if (CHECK(m_hr = m_pIAccessor->GetBindings(m_hAccessor, &dwFlags, &m_cBindings2,
|
|
&m_rgBindings2), S_OK))
|
|
{
|
|
//Do extended check following GetBindings
|
|
fResults &= XCHECK(m_pIAccessor, IID_IAccessor, m_hr);
|
|
}
|
|
|
|
m_pExtError->CauseError();
|
|
if (CHECK(m_hr = m_pIAccessor->ReleaseAccessor(m_hAccessor, NULL), S_OK))
|
|
{
|
|
|
|
//Do extended check following ReleaseAccessor
|
|
fResults &= XCHECK(m_pIAccessor, IID_IAccessor, m_hr);
|
|
}
|
|
else
|
|
fResults = FALSE;
|
|
|
|
m_hAccessor = DB_NULL_HACCESSOR;
|
|
|
|
}
|
|
|
|
|
|
PROVIDER_FREE(m_rgBindings2);
|
|
|
|
if (fResults)
|
|
return TEST_PASS;
|
|
else
|
|
return TEST_FAIL;
|
|
}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(2)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc Invalid IAccessor calls with previous error object existing
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCExtendedErrors::Variation_2()
|
|
{
|
|
BOOL fResults = FALSE;
|
|
DBACCESSORFLAGS dwFlags = 0;
|
|
HACCESSOR hAccessor;
|
|
|
|
|
|
//For each method of the interface, first create an error object on
|
|
//the current thread, then try get a failure from the IAccessor method.
|
|
//We then check extended errors to verify the right extended error behavior.
|
|
|
|
//Set first binding to invalid dwPart
|
|
m_rgBindings[0].dwPart = 0;
|
|
|
|
m_pExtError->CauseError();
|
|
|
|
//if (CHECK(m_hr = m_pCmdIAccessor->CreateAccessor(DBACCESSOR_ROWDATA, m_cBindings,
|
|
// m_rgBindings, 0, &hAccessor, NULL), DB_E_BADBINDINFO))
|
|
|
|
if (CHECK(m_hr = m_pIAccessor->CreateAccessor(DBACCESSOR_ROWDATA, m_cBindings,
|
|
m_rgBindings, 0, &hAccessor, m_rgStatus), DB_E_ERRORSOCCURRED))
|
|
{
|
|
fResults = COMPARE(m_rgStatus[0], DBBINDSTATUS_BADBINDINFO);
|
|
|
|
//Do extended check following CreateAccessor
|
|
fResults &= XCHECK(m_pIAccessor, IID_IAccessor, m_hr);
|
|
|
|
//NOTE: We released m_hAccessor in the Init, so
|
|
//the handle should be invalid
|
|
|
|
m_pExtError->CauseError();
|
|
//if (CHECK(m_hr = m_pCmdIAccessor->GetBindings(m_hAccessor, &dwFlags, &m_cBindings2,
|
|
if (CHECK(m_hr = m_pIAccessor->GetBindings(m_hAccessor, &dwFlags, &m_cBindings2,
|
|
&m_rgBindings2), DB_E_BADACCESSORHANDLE))
|
|
{
|
|
//Do extended check following GetBindings
|
|
fResults &= XCHECK(m_pIAccessor, IID_IAccessor, m_hr);
|
|
}
|
|
|
|
m_pExtError->CauseError();
|
|
//if (CHECK(m_hr = m_pCmdIAccessor->ReleaseAccessor(m_hAccessor, NULL), DB_E_BADACCESSORHANDLE))
|
|
if (CHECK(m_hr = m_pIAccessor->ReleaseAccessor(m_hAccessor, NULL), DB_E_BADACCESSORHANDLE))
|
|
{
|
|
//Do extended check following ReleaseAccessor
|
|
fResults &= XCHECK(m_pIAccessor, IID_IAccessor, m_hr);
|
|
}
|
|
else
|
|
fResults = FALSE;
|
|
|
|
m_hAccessor = DB_NULL_HACCESSOR;
|
|
}
|
|
|
|
|
|
PROVIDER_FREE(m_rgBindings2);
|
|
|
|
//Reset dwPart to valid value
|
|
m_rgBindings[0].dwPart = DBPART_VALUE | DBPART_LENGTH | DBPART_STATUS;
|
|
|
|
if (fResults)
|
|
return TEST_PASS;
|
|
else
|
|
return TEST_FAIL;
|
|
}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(3)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc Invalid IAccessor calls with no previous error object existing
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCExtendedErrors::Variation_3()
|
|
{
|
|
BOOL fResults = FALSE;
|
|
DBACCESSORFLAGS dwFlags = 0;
|
|
HACCESSOR hAccessor;
|
|
DBTYPE dbType;
|
|
|
|
|
|
//For each method of the interface, with no error object on
|
|
//the current thread, try get a failure from the IAccessor method.
|
|
//We then check extended errors to verify the right extended error behavior.
|
|
|
|
//Remember valid value for first binding's wType
|
|
dbType = m_rgBindings[0].wType;
|
|
|
|
//Set first binding wType to DBTYPE_EMPTY
|
|
m_rgBindings[0].wType = DBTYPE_EMPTY;
|
|
|
|
// if (CHECK(m_hr = m_pCmdIAccessor->CreateAccessor(DBACCESSOR_ROWDATA, m_cBindings,
|
|
// m_rgBindings, 0, &hAccessor, NULL), DB_E_BADBINDINFO))
|
|
|
|
if (CHECK(m_hr = m_pIAccessor->CreateAccessor(DBACCESSOR_ROWDATA, m_cBindings,
|
|
m_rgBindings, 0, &hAccessor, m_rgStatus), DB_E_ERRORSOCCURRED))
|
|
{
|
|
fResults = COMPARE(m_rgStatus[0], DBBINDSTATUS_BADBINDINFO);
|
|
|
|
//Do extended check following CreateAccessor
|
|
fResults &= XCHECK(m_pIAccessor, IID_IAccessor, m_hr);
|
|
|
|
//NOTE: We released m_hAccessor in the Init, so
|
|
//the handle should be invalid
|
|
|
|
//if (CHECK(m_hr = m_pCmdIAccessor->GetBindings(m_hAccessor, &dwFlags, &m_cBindings2,
|
|
if (CHECK(m_hr = m_pIAccessor->GetBindings(m_hAccessor, &dwFlags, &m_cBindings2,
|
|
&m_rgBindings2), DB_E_BADACCESSORHANDLE))
|
|
{
|
|
//Do extended check following GetBindings
|
|
fResults &= XCHECK(m_pIAccessor, IID_IAccessor, m_hr);
|
|
}
|
|
|
|
//if (CHECK(m_hr = m_pCmdIAccessor->ReleaseAccessor(m_hAccessor, NULL), DB_E_BADACCESSORHANDLE))
|
|
if (CHECK(m_hr = m_pIAccessor->ReleaseAccessor(m_hAccessor, NULL), DB_E_BADACCESSORHANDLE))
|
|
{
|
|
//Do extended check following ReleaseAccessor
|
|
fResults &= XCHECK(m_pIAccessor, IID_IAccessor, m_hr);
|
|
}
|
|
else
|
|
fResults = FALSE;
|
|
|
|
m_hAccessor = DB_NULL_HACCESSOR;
|
|
}
|
|
|
|
|
|
PROVIDER_FREE(m_rgBindings2);
|
|
|
|
//Reset wType to previous value
|
|
m_rgBindings[0].wType = dbType;
|
|
|
|
if (fResults)
|
|
return TEST_PASS;
|
|
else
|
|
return TEST_FAIL;
|
|
}
|
|
// }}
|
|
// {{ TCW_TERMINATE_METHOD
|
|
//--------------------------------------------------------------------
|
|
// @mfunc TestCase Termination Routine
|
|
//
|
|
// @rdesc TRUE or FALSE
|
|
//
|
|
BOOL TCExtendedErrors::Terminate()
|
|
{
|
|
|
|
SAFE_RELEASE(m_pIAccessor);
|
|
|
|
//Release everything we did after CAccessor::Init
|
|
FREE_BINDINGS(&m_cBindings, &m_rgBindings);
|
|
ReleaseRowsetObject();
|
|
|
|
// {{ TCW_TERM_BASECLASS_CHECK2
|
|
return(CAccessor::Terminate());
|
|
} // }}
|
|
// }}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_TC_PROTOTYPE(TCCrtRtnValsBeforeGetRows)
|
|
//*-----------------------------------------------------------------------
|
|
//| Test Case: TCCrtRtnValsBeforeGetRows - Return values for all CreateAccessor error conditions
|
|
//| Created: 03/27/96
|
|
//*-----------------------------------------------------------------------
|
|
|
|
//--------------------------------------------------------------------
|
|
// @mfunc TestCase Initialization Routine
|
|
//
|
|
// @rdesc TRUE or FALSE
|
|
//
|
|
BOOL TCCrtRtnValsBeforeGetRows::Init()
|
|
{
|
|
IColumnsInfo * pIColInfo = NULL;
|
|
ULONG cColumns = 0;
|
|
DBCOLUMNINFO * rgInfo = NULL;
|
|
WCHAR * pStrBuffer = NULL;
|
|
HRESULT hr;
|
|
|
|
// {{ TCW_INIT_BASECLASS_CHECK
|
|
if(CAccessor::Init())
|
|
// }}
|
|
{
|
|
//Set m_pIAccessor on a 'select *' rowset We'll
|
|
//use this interface ptr to do our tests.
|
|
if(g_fCmdSupported)
|
|
hr=CreateRowsetObject(SELECT_VALIDATIONORDER);
|
|
else
|
|
{
|
|
// Since deferred validation is only mandatory for accessors created from
|
|
// a command object then without commands we can't test.
|
|
odtLog << L"Commands not supported, can't test deferred validation.\n";
|
|
return TEST_SKIPPED;
|
|
}
|
|
|
|
if (CHECK(hr,S_OK))
|
|
{
|
|
//Fill in m_rgBindings, m_cBindings and m_cbRowSize with valid values
|
|
if (CHECK(GetAccessorAndBindings(m_pIAccessor, DBACCESSOR_ROWDATA,
|
|
&m_hAccessor, &m_rgBindings, &m_cBindings, &m_cbRowSize,
|
|
DBPART_VALUE | DBPART_LENGTH | DBPART_STATUS,
|
|
ALL_COLS_BOUND,
|
|
FORWARD, NO_COLS_BY_REF, NULL, NULL,
|
|
NULL, DBTYPE_EMPTY, 0, NULL, NULL,
|
|
NO_COLS_OWNED_BY_PROV, DBPARAMIO_NOTPARAM,
|
|
m_fBindLongCols),S_OK))
|
|
{
|
|
//We don't need this accessor, we just wanted to generate
|
|
//bindings to be used in an attempt to create other accessors
|
|
CHECK(m_pIAccessor->ReleaseAccessor(m_hAccessor, NULL), S_OK);
|
|
m_hAccessor = DB_NULL_HACCESSOR;
|
|
|
|
//We want a clean start for every variation, so release rowset here
|
|
ReleaseRowsetObject();
|
|
return TRUE;
|
|
}
|
|
}
|
|
else
|
|
return FALSE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(1)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc DB_E_BADBINDINFO - PASSBYREF without correct buffer format
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCCrtRtnValsBeforeGetRows::Variation_1()
|
|
{
|
|
|
|
BOOL fResults = FALSE;
|
|
DBBYTEOFFSET obValue;
|
|
DBLENGTH cbMaxLen;
|
|
HRESULT hr;
|
|
|
|
//Start fresh with a rowset where no rows have
|
|
//been gotten, to attempt force deferred validation, if applicable.
|
|
hr=CreateRowsetObject(SELECT_VALIDATIONORDER);
|
|
|
|
if (CHECK(hr,S_OK))
|
|
{
|
|
if (m_fPassByRef)
|
|
{
|
|
|
|
//Remember the values we will be changing
|
|
obValue = m_rgBindings[0].obValue;
|
|
cbMaxLen = m_rgBindings[0].cbMaxLen;
|
|
|
|
//Ensure our buffer does not match the provider's by
|
|
//setting the cbMaxLen to 0 and the obValue to an offset of 1.
|
|
//A cbMaxLen of 0 should never occur for variable length data.
|
|
//In case of fixed length data, we use an obValue of 1, which is based
|
|
//on an assumption that no provider will skip one byte and then
|
|
//start the value buffer.
|
|
m_rgBindings[0].cbMaxLen = 0;
|
|
m_rgBindings[0].obValue = 1;
|
|
|
|
//Try PASSBYREF with bindings that don't match provider's buffer layout
|
|
m_hr =m_pIAccessor->CreateAccessor(DBACCESSOR_ROWDATA | DBACCESSOR_PASSBYREF,
|
|
m_cBindings, m_rgBindings, m_cbRowSize, &m_hAccessor, m_rgStatus);
|
|
|
|
//Verify return code - may be deferred mode
|
|
fResults = VerifyError(m_pIAccessor, m_hAccessor, DB_E_BADBINDINFO, DBBINDSTATUS_BADBINDINFO,
|
|
0, m_rgBindings, MAY_DEFERR, MUST_FAIL);
|
|
|
|
//Reset cbMaxLen and value offset to previous values
|
|
m_rgBindings[0].cbMaxLen = cbMaxLen;
|
|
m_rgBindings[0].obValue = obValue;
|
|
}
|
|
else
|
|
{
|
|
//Should fail outright, without having mismatching buffers
|
|
CHECKW(m_pIAccessor->CreateAccessor(DBACCESSOR_ROWDATA | DBACCESSOR_PASSBYREF,
|
|
m_cBindings, m_rgBindings, m_cbRowSize, &m_hAccessor, m_rgStatus),
|
|
DB_E_BYREFACCESSORNOTSUPPORTED);
|
|
|
|
fResults = TRUE;
|
|
}
|
|
|
|
|
|
ReleaseRowsetObject();
|
|
}
|
|
|
|
SAFE_RELEASE_ACCESSOR(m_pIAccessor, m_hAccessor);
|
|
|
|
if (fResults)
|
|
return TEST_PASS;
|
|
else
|
|
return TEST_FAIL;
|
|
}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(2)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc DB_E_BADBINDINFO - DBMEMOWNER_PROVIDEROWNED with DBTYPE not matching provider's
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCCrtRtnValsBeforeGetRows::Variation_2()
|
|
{
|
|
|
|
BOOL fResults = FALSE;
|
|
DBTYPE wType;
|
|
ULONG i=0;
|
|
HRESULT hr;
|
|
|
|
//Start fresh with a rowset where no rows have
|
|
//been gotten, to attempt force deferred validation, if applicable.
|
|
hr=CreateRowsetObject(SELECT_VALIDATIONORDER);
|
|
|
|
if (CHECK(hr,S_OK))
|
|
{
|
|
//Find a column which own't convert to IUnknown
|
|
for (i=0; i < m_cBindings; i++)
|
|
{
|
|
if (m_rgBindings[i].wType != DBTYPE_IUNKNOWN &&
|
|
m_rgBindings[i].wType != DBTYPE_IDISPATCH &&
|
|
m_rgBindings[i].wType != DBTYPE_BYTES &&
|
|
m_rgBindings[i].wType != DBTYPE_WSTR &&
|
|
m_rgBindings[i].wType != DBTYPE_STR)
|
|
break;
|
|
}
|
|
|
|
//Assume we have at least one non IUnknown convertable column, or we'll fail
|
|
if (i == m_cBindings)
|
|
{
|
|
odtLog << L"No IUnknown convertable column. \n";
|
|
return TEST_SKIPPED;
|
|
}
|
|
|
|
//Remember the wType which we will be changing
|
|
wType = m_rgBindings[i].wType;
|
|
|
|
//Use BYREF on the non IUnknown column's binding, and ensure our requested
|
|
//wType does not match the provider's by using DBTYPE_IUNKNOWN
|
|
m_rgBindings[i].wType = DBTYPE_BYREF | DBTYPE_IUNKNOWN;
|
|
|
|
//Make the binding provider owned
|
|
m_rgBindings[i].dwMemOwner = DBMEMOWNER_PROVIDEROWNED;
|
|
|
|
//Try DBMEMOWNER_PROVIDEROWNED with a binding type which doesn't match the provider's
|
|
m_hr =m_pIAccessor->CreateAccessor(DBACCESSOR_ROWDATA,
|
|
m_cBindings, m_rgBindings, m_cbRowSize, &m_hAccessor, m_rgStatus);
|
|
|
|
//Verify return code -- may be deferred
|
|
fResults = VerifyError(m_pIAccessor, m_hAccessor, DB_E_BADBINDINFO, DBBINDSTATUS_BADBINDINFO,
|
|
i, m_rgBindings, MAY_DEFERR, MUST_FAIL);
|
|
|
|
//Reset correct type of binding we changed
|
|
m_rgBindings[i].wType = wType;
|
|
//Reset owner to client
|
|
m_rgBindings[i].dwMemOwner = DBMEMOWNER_CLIENTOWNED;
|
|
|
|
ReleaseRowsetObject();
|
|
|
|
}
|
|
|
|
if (fResults)
|
|
return TEST_PASS;
|
|
else
|
|
return TEST_FAIL;
|
|
}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(3)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc DB_E_BADBINDINFO - Accessor with invalid coersion for column in existing optimized accessor
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCCrtRtnValsBeforeGetRows::Variation_3()
|
|
{
|
|
TESTRESULT fResults = TEST_FAIL;
|
|
HACCESSOR hOptAccessor = DB_NULL_HACCESSOR;
|
|
HACCESSOR hAccessor = DB_NULL_HACCESSOR;
|
|
ULONG iBackEndType;
|
|
DBTYPE wType = DBTYPE_EMPTY, wOptType, wNonOptType;
|
|
HRESULT hr;
|
|
BYTE * pData=NULL;
|
|
|
|
//Start fresh with a rowset where no rows have
|
|
//been gotten, to attempt force deferred validation, if applicable.
|
|
hr=CreateRowsetObject(SELECT_VALIDATIONORDER);
|
|
|
|
/*
|
|
Find binding indexes of bad types for this variation. We need:
|
|
1) Backend DBTYPE can convert to Optimized accessor DBTYPE
|
|
2) Backend DBTYPE can convert to NonOptimized accessor DBTYPE
|
|
3) Optimized accessor DBTYPE can't convert to NonOptimized accessor DBTYPE
|
|
|
|
This assumes the existing binding array has all columns bound to have all types
|
|
available.
|
|
*/
|
|
if (!FindConversionTypes(m_rgBindings, m_cBindings, &iBackEndType, &wOptType, &wNonOptType))
|
|
{
|
|
odtLog <<L"Can't find a combination of data types required for this variation.\n";
|
|
fResults = TEST_SKIPPED;
|
|
goto CLEANUP;
|
|
}
|
|
|
|
if (CHECK(hr,S_OK))
|
|
{
|
|
//Remember value we'll be changing
|
|
wType = m_rgBindings[iBackEndType].wType;
|
|
|
|
m_rgBindings[iBackEndType].wType = wOptType;
|
|
|
|
// Create first optimized accessor. Note providers that don't support optimized
|
|
// accessors generally ignore the OPTIMIZED flag and just create a regular
|
|
// accessor.
|
|
TESTC_(m_pIAccessor->CreateAccessor(DBACCESSOR_ROWDATA | DBACCESSOR_OPTIMIZED,
|
|
1, &m_rgBindings[iBackEndType], m_cbRowSize, &hOptAccessor, m_rgStatus),
|
|
S_OK);
|
|
|
|
m_rgBindings[iBackEndType].wType = wNonOptType;
|
|
|
|
//Now try to create a second accessor for same column,
|
|
//and use an unsupported coersion of DBTYPE_IUNKNOWN
|
|
m_hr = m_pIAccessor->CreateAccessor(DBACCESSOR_ROWDATA,
|
|
1, &m_rgBindings[iBackEndType], m_cbRowSize, &hAccessor, m_rgStatus);
|
|
|
|
//Verify return code -- may be deferred
|
|
TESTC(VerifyError(m_pIAccessor, hAccessor, DB_E_BADBINDINFO, DBBINDSTATUS_BADBINDINFO,
|
|
0, &m_rgBindings[iBackEndType], MAY_DEFERR, MAY_FAIL));
|
|
|
|
}
|
|
|
|
fResults = TEST_PASS;
|
|
|
|
CLEANUP:
|
|
|
|
if (wType != DBTYPE_EMPTY)
|
|
//Set back type we changed in binding
|
|
m_rgBindings[iBackEndType].wType = wType;
|
|
|
|
//Release the first optimized accessor
|
|
if (hOptAccessor)
|
|
CHECK(m_pIAccessor->ReleaseAccessor(hOptAccessor, NULL),S_OK);
|
|
//Release the second accessor
|
|
if (hAccessor)
|
|
CHECK(m_pIAccessor->ReleaseAccessor(hAccessor, NULL),S_OK);
|
|
|
|
ReleaseRowsetObject();
|
|
|
|
return fResults;
|
|
}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(4)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc DB_E_BADORDINAL - iOrdinal of largest column number + 1
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCCrtRtnValsBeforeGetRows::Variation_4()
|
|
{
|
|
DBORDINAL ulRememberOrdinal = 0;
|
|
BOOL fResults = FALSE;
|
|
HRESULT hr;
|
|
|
|
//Start fresh with a rowset where no rows have
|
|
//been gotten, to attempt force deferred validation, if applicable.
|
|
hr=CreateRowsetObject(SELECT_VALIDATIONORDER);
|
|
|
|
if (CHECK(hr, S_OK))
|
|
{
|
|
//Set column number one too large
|
|
ulRememberOrdinal = m_rgBindings[0].iOrdinal;
|
|
//Number of possible columns plus 1 (for bookmark)
|
|
//plus 1 should be invalid
|
|
m_rgBindings[0].iOrdinal = m_pTable->CountColumnsOnTable()+2;
|
|
|
|
//Should be invalid column number
|
|
m_hr = m_pIAccessor->CreateAccessor(DBACCESSOR_ROWDATA,m_cBindings,
|
|
m_rgBindings, m_cbRowSize, &m_hAccessor, m_rgStatus);
|
|
|
|
//Verify return code -- may be deferred
|
|
fResults = VerifyError(m_pIAccessor, m_hAccessor, DB_E_BADORDINAL, DBBINDSTATUS_BADORDINAL,
|
|
0, m_rgBindings, MAY_DEFERR, MUST_FAIL);
|
|
|
|
//Set correct column number back
|
|
m_rgBindings[0].iOrdinal = ulRememberOrdinal;
|
|
|
|
ReleaseRowsetObject();
|
|
}
|
|
|
|
if (fResults)
|
|
return TEST_PASS;
|
|
else
|
|
return TEST_FAIL;
|
|
|
|
}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(5)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc DB_E_BADORDINAL - iOrdinal of max value for ULONG
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCCrtRtnValsBeforeGetRows::Variation_5()
|
|
{
|
|
BOOL fResults = FALSE;
|
|
ULONG ulMax;
|
|
DBORDINAL ulRememberOrdinal;
|
|
HRESULT hr;
|
|
|
|
//Start fresh with a rowset where no rows have
|
|
//been gotten, to attempt force deferred validation, if applicable.
|
|
hr=CreateRowsetObject(SELECT_VALIDATIONORDER);
|
|
|
|
if (CHECK(hr,S_OK))
|
|
{
|
|
|
|
//Get the max number a ULONG can hold
|
|
ulMax = ULONG_MAX;
|
|
|
|
ulRememberOrdinal = m_rgBindings[0].iOrdinal;
|
|
|
|
//Set column number to max ULONG possible
|
|
m_rgBindings[0].iOrdinal = ulMax;
|
|
|
|
//Max number the type can hold should be invalid column number
|
|
m_hr = m_pIAccessor->CreateAccessor(DBACCESSOR_ROWDATA, m_cBindings,
|
|
m_rgBindings, m_cbRowSize, &m_hAccessor, m_rgStatus);
|
|
|
|
//Verify return code -- may be deferred
|
|
fResults = VerifyError(m_pIAccessor, m_hAccessor, DB_E_BADORDINAL, DBBINDSTATUS_BADORDINAL,
|
|
0, m_rgBindings, MAY_DEFERR, MUST_FAIL);
|
|
|
|
//Set correct column number back
|
|
m_rgBindings[0].iOrdinal = ulRememberOrdinal;
|
|
|
|
ReleaseRowsetObject();
|
|
|
|
}
|
|
|
|
if (fResults)
|
|
return TEST_PASS;
|
|
else
|
|
return TEST_FAIL;
|
|
}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(6)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc DB_E_BADORDINAL - iOrdinal = 0 for ROWDATA accessor without bookmarks
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCCrtRtnValsBeforeGetRows::Variation_6()
|
|
{
|
|
DBACCESSORFLAGS dwAccessorFlags;
|
|
DBORDINAL cCols = 0;
|
|
DBORDINAL iCol = 0;
|
|
DBTYPE dbType;
|
|
BOOL fResults = FALSE;
|
|
IColumnsInfo * pIColInfo = NULL;
|
|
DBCOLUMNINFO * rgInfo = NULL;
|
|
WCHAR * pStrings = NULL;
|
|
BOOL fBkmkVisible = FALSE;
|
|
HRESULT hr;
|
|
|
|
//Start fresh with a rowset where no rows have
|
|
//been gotten, to force possible deferred validation.
|
|
hr=CreateRowsetObject(SELECT_VALIDATIONORDER);
|
|
|
|
if (CHECK(hr,S_OK))
|
|
{
|
|
|
|
//Find out if provider exposes column 0 itself before we go any farther
|
|
if (!VerifyInterface(m_pIAccessor, IID_IColumnsInfo,
|
|
ROWSET_INTERFACE, (IUnknown **)&pIColInfo))
|
|
goto CLEANUP;
|
|
|
|
if (CHECK(pIColInfo->GetColumnInfo(&cCols, &rgInfo,
|
|
&pStrings), S_OK))
|
|
{
|
|
//Bookmark column exists on rowset
|
|
if (rgInfo[0].iOrdinal == 0)
|
|
fBkmkVisible = TRUE;
|
|
|
|
PROVIDER_FREE(rgInfo);
|
|
PROVIDER_FREE(pStrings);
|
|
SAFE_RELEASE(pIColInfo);
|
|
|
|
}
|
|
else
|
|
goto CLEANUP;
|
|
|
|
//Set up parameter flags
|
|
dwAccessorFlags = DBACCESSOR_ROWDATA;
|
|
|
|
//Swap in column zero bound to string for first binding
|
|
iCol = m_rgBindings[0].iOrdinal;
|
|
dbType = m_rgBindings[0].wType;
|
|
m_rgBindings[0].iOrdinal = 0;
|
|
m_rgBindings[0].wType = DBTYPE_STR;
|
|
|
|
//Column zero is valid and should succeed
|
|
if (fBkmkVisible)
|
|
{
|
|
if (CHECK(m_pIAccessor->CreateAccessor(dwAccessorFlags,
|
|
m_cBindings, m_rgBindings, m_cbRowSize,
|
|
&m_hAccessor, m_rgStatus), S_OK))
|
|
{
|
|
fResults = CHECK(m_pIAccessor->ReleaseAccessor(m_hAccessor, NULL), S_OK);
|
|
m_hAccessor = DB_NULL_HACCESSOR;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//Column zero should fail as bookmark does not exist
|
|
m_hr = m_pIAccessor->CreateAccessor(dwAccessorFlags,
|
|
m_cBindings, m_rgBindings, m_cbRowSize, &m_hAccessor, m_rgStatus);
|
|
|
|
//Verify return code -- may be deferred
|
|
fResults = VerifyError(m_pIAccessor, m_hAccessor, DB_E_BADORDINAL, DBBINDSTATUS_BADORDINAL,
|
|
0, m_rgBindings, MAY_DEFERR, MUST_FAIL);
|
|
}
|
|
|
|
//Set bindings back the way they were
|
|
m_rgBindings[0].iOrdinal = iCol;
|
|
m_rgBindings[0].wType = dbType;
|
|
|
|
}
|
|
|
|
CLEANUP:
|
|
|
|
ReleaseRowsetObject();
|
|
|
|
if (fResults)
|
|
return TEST_PASS;
|
|
else
|
|
return TEST_FAIL;
|
|
|
|
}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(7)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc DB_E_BADBINDINFO - Some bindings succeeding others failing
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCCrtRtnValsBeforeGetRows::Variation_7()
|
|
{
|
|
BOOL fResults = FALSE;
|
|
HACCESSOR hOptAccessor = DB_NULL_HACCESSOR;
|
|
ULONG iBackEndType;
|
|
DBTYPE wType, wOptType, wNonOptType;
|
|
HRESULT hr;
|
|
BYTE * pData=NULL;
|
|
|
|
//The point of this variation is to repeat variation 3 , but
|
|
//to use some successful bindings as well as the failing
|
|
//binding
|
|
|
|
//Start fresh with a rowset where no rows have
|
|
//been gotten, to attempt force deferred validation, if applicable.
|
|
hr=CreateRowsetObject(SELECT_VALIDATIONORDER);
|
|
|
|
if (CHECK(hr,S_OK))
|
|
{
|
|
|
|
/*
|
|
Find binding indexes of bad types for this variation. We need:
|
|
1) Backend DBTYPE can convert to Optimized accessor DBTYPE
|
|
2) Backend DBTYPE can convert to NonOptimized accessor DBTYPE
|
|
3) Optimized accessor DBTYPE can't convert to NonOptimized accessor DBTYPE
|
|
|
|
This assumes the existing binding array has all columns bound to have all types
|
|
available.
|
|
*/
|
|
if (!FindConversionTypes(m_rgBindings, m_cBindings, &iBackEndType, &wOptType, &wNonOptType))
|
|
{
|
|
odtLog <<L"Can't find a combination of data types required for this variation.\n";
|
|
return TEST_SKIPPED;
|
|
}
|
|
|
|
//Remember value we'll be changing
|
|
wType = m_rgBindings[iBackEndType].wType;
|
|
|
|
m_rgBindings[iBackEndType].wType = wOptType;
|
|
|
|
//Create one optimized accessor with one non IUnknown column, and
|
|
//one column of whatever is next in the binding array
|
|
if (!CHECK(m_pIAccessor->CreateAccessor(DBACCESSOR_ROWDATA | DBACCESSOR_OPTIMIZED,
|
|
2, &m_rgBindings[iBackEndType], m_cbRowSize, &hOptAccessor, m_rgStatus),
|
|
S_OK))
|
|
return TEST_FAIL;
|
|
|
|
m_rgBindings[iBackEndType].wType = wNonOptType;
|
|
|
|
//Now try to create a second accessor for same column,
|
|
//and use an unsupported coersion of DBTYPE_IUNKNOWN for
|
|
//binding one, and a valid binding for binding two
|
|
m_hr = m_pIAccessor->CreateAccessor(DBACCESSOR_ROWDATA,
|
|
2, &m_rgBindings[iBackEndType], m_cbRowSize, &m_hAccessor, m_rgStatus);
|
|
|
|
//Verify return code -- may be deferred
|
|
fResults = VerifyError(m_pIAccessor, m_hAccessor, DB_E_BADBINDINFO, DBBINDSTATUS_BADBINDINFO,
|
|
0, &m_rgBindings[iBackEndType], MAY_DEFERR, MAY_FAIL);
|
|
|
|
//Release the first optimized accessor
|
|
if (hOptAccessor)
|
|
CHECK(m_pIAccessor->ReleaseAccessor(hOptAccessor, NULL),S_OK);
|
|
//Set back type we changed in binding
|
|
m_rgBindings[iBackEndType].wType = wType;
|
|
|
|
ReleaseRowsetObject();
|
|
}
|
|
|
|
if (fResults)
|
|
return TEST_PASS;
|
|
else
|
|
return TEST_FAIL;
|
|
|
|
}
|
|
// }}
|
|
// {{ TCW_TERMINATE_METHOD
|
|
//--------------------------------------------------------------------
|
|
// @mfunc TestCase Termination Routine
|
|
//
|
|
// @rdesc TRUE or FALSE
|
|
//
|
|
BOOL TCCrtRtnValsBeforeGetRows::Terminate()
|
|
{
|
|
|
|
//Cleanup everything we created in TCCrtRtnValsBeforeGetRows::Init()
|
|
FREE_BINDINGS(&m_cBindings, &m_rgBindings);
|
|
ReleaseRowsetObject();
|
|
|
|
return(CAccessor::Terminate());
|
|
}
|
|
// }}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_TC_PROTOTYPE(TCAddRefAccessor)
|
|
//*-----------------------------------------------------------------------
|
|
//| Test Case: TCAddRefAccessor - Test the AddREfAccessor Method
|
|
//| Created: 07/30/96
|
|
//*-----------------------------------------------------------------------
|
|
|
|
//--------------------------------------------------------------------
|
|
// @mfunc TestCase Initialization Routine
|
|
//
|
|
// @rdesc TRUE or FALSE
|
|
//
|
|
BOOL TCAddRefAccessor::Init()
|
|
{
|
|
|
|
BOOL fSuccess = FALSE;
|
|
HRESULT hr;
|
|
|
|
// {{ TCW_INIT_BASECLASS_CHECK
|
|
if(CAccessor::Init())
|
|
// }}
|
|
{
|
|
hr=CreateRowsetObject(SELECT_VALIDATIONORDER);
|
|
|
|
//Set m_pIAccessor on a 'select *' rowset We'll
|
|
//use this interface ptr to do our tests.
|
|
if (CHECK(hr,S_OK))
|
|
{
|
|
if(m_pICommand)
|
|
{
|
|
//Make sure we don't get Open Object error
|
|
ReleaseRowsetObject();
|
|
|
|
//Get IAccesor on Command
|
|
if (VerifyInterface(m_pICommand,IID_IAccessor,COMMAND_INTERFACE,
|
|
(IUnknown **)&m_pCmdIAccessor))
|
|
//Create an accessor on the command object
|
|
if (CHECK(GetAccessorAndBindings(m_pCmdIAccessor, DBACCESSOR_ROWDATA,
|
|
&m_hAccessor, &m_rgBindings, &m_cBindings, &m_cbRowSize,
|
|
DBPART_VALUE | DBPART_LENGTH | DBPART_STATUS,
|
|
ALL_COLS_BOUND,
|
|
FORWARD, NO_COLS_BY_REF, NULL, NULL,
|
|
NULL, DBTYPE_EMPTY, 0, NULL, NULL,
|
|
NO_COLS_OWNED_BY_PROV, DBPARAMIO_NOTPARAM,
|
|
m_fBindLongCols),S_OK))
|
|
//Now create rowset again
|
|
if (!CHECK(CreateRowsetObject(SELECT_VALIDATIONORDER),S_OK))
|
|
return TEST_FAIL;
|
|
}
|
|
//Create an accessor on the rowset object
|
|
if (CHECK(GetAccessorAndBindings(m_pIAccessor, DBACCESSOR_ROWDATA,
|
|
&m_hAccessor2, &m_rgBindings2, &m_cBindings2, &m_cbRowSize2,
|
|
DBPART_VALUE | DBPART_LENGTH | DBPART_STATUS,
|
|
ALL_COLS_BOUND,
|
|
FORWARD, NO_COLS_BY_REF, NULL, NULL,
|
|
NULL, DBTYPE_EMPTY, 0, NULL, NULL,
|
|
NO_COLS_OWNED_BY_PROV, DBPARAMIO_NOTPARAM,
|
|
m_fBindLongCols),S_OK))
|
|
|
|
fSuccess = TRUE;
|
|
}
|
|
}
|
|
|
|
|
|
return fSuccess;
|
|
}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(1)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc Regular Addreff on an accessor, S_OK
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCAddRefAccessor::Variation_1()
|
|
{
|
|
BOOL fSuccess = FALSE;
|
|
ULONG cCmdRefCount = 1;
|
|
ULONG cRowsetRefCount = 1;
|
|
ULONG cCmdRefCountOnRel = 1;
|
|
ULONG cRowsetRefCountOnRel = 1;
|
|
|
|
if(m_pCmdIAccessor)
|
|
{
|
|
// Check the refcount on both cmd and rowset accessors;
|
|
if (!CHECK (m_pCmdIAccessor->AddRefAccessor (m_hAccessor, &cCmdRefCount), S_OK))
|
|
goto CLEANUP;
|
|
|
|
if (!COMPARE (cCmdRefCount, 2))
|
|
goto CLEANUP;
|
|
|
|
// Do it again.
|
|
if (!CHECK (m_pCmdIAccessor->AddRefAccessor (m_hAccessor, &cCmdRefCount), S_OK))
|
|
goto CLEANUP;
|
|
|
|
if (!COMPARE (cCmdRefCount, 3))
|
|
goto CLEANUP;
|
|
}
|
|
|
|
// Do it for accessor on rowset.
|
|
if (!CHECK (m_pIAccessor->AddRefAccessor (m_hAccessor2, &cRowsetRefCount), S_OK))
|
|
goto CLEANUP;
|
|
|
|
if (!COMPARE (cRowsetRefCount, 2))
|
|
goto CLEANUP;
|
|
|
|
|
|
if (!CHECK (m_pIAccessor->AddRefAccessor (m_hAccessor2, &cRowsetRefCount), S_OK))
|
|
goto CLEANUP;
|
|
|
|
if (!COMPARE (cRowsetRefCount, 3))
|
|
goto CLEANUP;
|
|
|
|
if(m_pCmdIAccessor)
|
|
{
|
|
if (!CHECK (m_pCmdIAccessor->ReleaseAccessor(m_hAccessor, &cCmdRefCountOnRel), S_OK))
|
|
goto CLEANUP;
|
|
|
|
if (!COMPARE (cCmdRefCountOnRel, cCmdRefCount -1))
|
|
goto CLEANUP;
|
|
|
|
cCmdRefCount--;
|
|
|
|
if (!CHECK (m_pCmdIAccessor->ReleaseAccessor(m_hAccessor, &cCmdRefCountOnRel), S_OK))
|
|
goto CLEANUP;
|
|
|
|
if (!COMPARE (cCmdRefCountOnRel, cCmdRefCount -1))
|
|
goto CLEANUP;
|
|
|
|
cCmdRefCount--;
|
|
}
|
|
|
|
if (!CHECK (m_pIAccessor->ReleaseAccessor(m_hAccessor2, &cRowsetRefCountOnRel), S_OK ))
|
|
goto CLEANUP;
|
|
|
|
if (!COMPARE (cRowsetRefCountOnRel, cRowsetRefCount - 1))
|
|
goto CLEANUP;
|
|
|
|
cRowsetRefCount--;
|
|
|
|
if (!CHECK (m_pIAccessor->ReleaseAccessor(m_hAccessor2, &cRowsetRefCountOnRel), S_OK ))
|
|
goto CLEANUP;
|
|
|
|
if (!COMPARE (cRowsetRefCountOnRel, cRowsetRefCount - 1))
|
|
goto CLEANUP;
|
|
|
|
cRowsetRefCount--;
|
|
|
|
fSuccess = TRUE;
|
|
|
|
CLEANUP:
|
|
|
|
while (cRowsetRefCount > 1)
|
|
m_pIAccessor->ReleaseAccessor (m_hAccessor2, &cRowsetRefCount);
|
|
|
|
while (m_pCmdIAccessor && cCmdRefCountOnRel > 1)
|
|
m_pCmdIAccessor->ReleaseAccessor(m_hAccessor, &cCmdRefCount);
|
|
|
|
if (fSuccess)
|
|
return TEST_PASS;
|
|
else
|
|
return TEST_FAIL;
|
|
}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(2)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc Addref on Command and Rowset object.
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCAddRefAccessor::Variation_2()
|
|
{
|
|
BOOL fSuccess = FALSE;
|
|
|
|
ULONG cCmdRefCount = 1;
|
|
ULONG cRowsetRefCount = 1;
|
|
|
|
// Now m_hAccessor is a command accessor. In should have been copied
|
|
// individual accessors.
|
|
if(g_fCmdSupported)
|
|
{
|
|
TESTC_(m_pCmdIAccessor->AddRefAccessor (m_hAccessor, &cCmdRefCount), S_OK);
|
|
|
|
COMPARE (cCmdRefCount, 2);
|
|
|
|
TESTC_(m_pCmdIAccessor->ReleaseAccessor (m_hAccessor, &cCmdRefCount), S_OK);
|
|
|
|
COMPARE (cCmdRefCount, 1);
|
|
}
|
|
|
|
|
|
// Do it for the rowset accessor.
|
|
TESTC_(m_pIAccessor->AddRefAccessor (m_hAccessor2, &cRowsetRefCount), S_OK);
|
|
|
|
COMPARE (cRowsetRefCount, 2);
|
|
|
|
TESTC_(m_pIAccessor->ReleaseAccessor (m_hAccessor2, &cRowsetRefCount), S_OK);
|
|
|
|
COMPARE (cRowsetRefCount, 1);
|
|
|
|
fSuccess = TRUE;
|
|
|
|
CLEANUP:
|
|
|
|
return TEST_PASS;
|
|
}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(3)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc NULL for pcRefCount arguments.
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCAddRefAccessor::Variation_3()
|
|
{
|
|
ULONG cCmdRefCount = 1;
|
|
ULONG cRowsetRefCount = 1;
|
|
BOOL fSuccess = FALSE;
|
|
|
|
if(g_fCmdSupported)
|
|
{
|
|
// Make ref count 2.
|
|
if (!CHECK (m_pCmdIAccessor->AddRefAccessor (m_hAccessor, NULL), S_OK))
|
|
goto CLEANUP;
|
|
|
|
// Make ref count 3
|
|
if (!CHECK (m_pCmdIAccessor->AddRefAccessor (m_hAccessor, NULL), S_OK))
|
|
goto CLEANUP;
|
|
|
|
// Make ref count 4.
|
|
if (!CHECK (m_pCmdIAccessor->AddRefAccessor (m_hAccessor, &cCmdRefCount), S_OK))
|
|
goto CLEANUP;
|
|
|
|
if (!COMPARE (cCmdRefCount, 4))
|
|
goto CLEANUP;
|
|
}
|
|
|
|
// Do it for the copied accessor.
|
|
if (!CHECK (m_pIAccessor->AddRefAccessor (m_hAccessor2, NULL), S_OK))
|
|
goto CLEANUP;
|
|
|
|
if (!CHECK (m_pIAccessor->AddRefAccessor (m_hAccessor2, NULL), S_OK))
|
|
goto CLEANUP;
|
|
|
|
if (!CHECK (m_pIAccessor->AddRefAccessor (m_hAccessor2, &cRowsetRefCount), S_OK))
|
|
goto CLEANUP;
|
|
|
|
fSuccess = TRUE;
|
|
|
|
CLEANUP:
|
|
|
|
// Retain the original ref count.
|
|
while (cRowsetRefCount > 1)
|
|
m_pIAccessor->ReleaseAccessor(m_hAccessor2, &cRowsetRefCount);
|
|
|
|
if(g_fCmdSupported)
|
|
{
|
|
while (m_pCmdIAccessor && cCmdRefCount > 1)
|
|
m_pCmdIAccessor->ReleaseAccessor (m_hAccessor, &cCmdRefCount);
|
|
}
|
|
|
|
return TEST_PASS;
|
|
|
|
}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(4)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc Invalid Accessor
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCAddRefAccessor::Variation_4()
|
|
{
|
|
BOOL fResult = TEST_PASS;
|
|
|
|
if (!CHECK(m_pIAccessor->AddRefAccessor(DB_NULL_HACCESSOR, NULL), DB_E_BADACCESSORHANDLE ) )
|
|
fResult = TEST_FAIL;
|
|
|
|
if(g_fCmdSupported)
|
|
{
|
|
if(!m_pCmdIAccessor)
|
|
return TEST_FAIL;
|
|
|
|
if (!CHECK (m_pCmdIAccessor->AddRefAccessor(DB_NULL_HACCESSOR, NULL), DB_E_BADACCESSORHANDLE ) )
|
|
fResult = TEST_FAIL;
|
|
}
|
|
|
|
return fResult;
|
|
}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(5)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc Release accessor on a rowset object.
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCAddRefAccessor::Variation_5()
|
|
{
|
|
// In this test case Add reff cmd accessor and release rowset accessor.
|
|
// Verify Release returns S_OK on the Last ref count.
|
|
|
|
BOOL fSuccess = FALSE;
|
|
ULONG cCmdRefCount = 1;
|
|
ULONG cRowsetRefCount = 1;
|
|
|
|
if(g_fCmdSupported)
|
|
{
|
|
// Now m_hAccessor is a command accessor. In should have been copied
|
|
// individual accessors.
|
|
if (!CHECK (m_pCmdIAccessor->AddRefAccessor (m_hAccessor, &cCmdRefCount), S_OK))
|
|
goto CLEANUP;
|
|
|
|
if (!COMPARE (cCmdRefCount, 2))
|
|
goto CLEANUP;
|
|
}
|
|
|
|
// Do it for the copied accessor.
|
|
if (!CHECK (m_pIAccessor->AddRefAccessor (m_hAccessor2, &cRowsetRefCount), S_OK))
|
|
goto CLEANUP;
|
|
|
|
if (!COMPARE (cRowsetRefCount, 2))
|
|
goto CLEANUP;
|
|
|
|
// Make sure only once ref count is left on Rowset accessor.
|
|
while (cRowsetRefCount > 1)
|
|
m_pIAccessor->ReleaseAccessor(m_hAccessor2, &cRowsetRefCount);
|
|
|
|
// Now addRef the CmdAccessor and Check for RefCount to be 3.
|
|
if(m_pCmdIAccessor)
|
|
{
|
|
if (!CHECK (m_pCmdIAccessor->AddRefAccessor (m_hAccessor, &cCmdRefCount), S_OK))
|
|
goto CLEANUP;
|
|
|
|
if (!COMPARE (cCmdRefCount, 3))
|
|
goto CLEANUP;
|
|
}
|
|
|
|
fSuccess = TRUE;
|
|
CLEANUP:
|
|
|
|
// Retain the original Ref count.
|
|
while (m_pCmdIAccessor && cCmdRefCount > 1)
|
|
m_pCmdIAccessor->ReleaseAccessor(m_hAccessor, &cCmdRefCount);
|
|
|
|
while (cRowsetRefCount > 1)
|
|
m_pIAccessor->ReleaseAccessor(m_hAccessor2, &cRowsetRefCount);
|
|
|
|
return TEST_PASS;
|
|
|
|
}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_TERMINATE_METHOD
|
|
//--------------------------------------------------------------------
|
|
// @mfunc TestCase Termination Routine
|
|
//
|
|
// @rdesc TRUE or FALSE
|
|
//
|
|
BOOL TCAddRefAccessor::Terminate()
|
|
{
|
|
FREE_BINDINGS(&m_cBindings, &m_rgBindings);
|
|
FREE_BINDINGS(&m_cBindings2, &m_rgBindings2);
|
|
ReleaseRowsetObject();
|
|
SAFE_RELEASE(m_pCmdIAccessor);
|
|
|
|
// {{ TCW_TERM_BASECLASS_CHECK2
|
|
return(CAccessor::Terminate());
|
|
} // }}
|
|
// }}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_TC_PROTOTYPE(TCAccessorOnAlteredTable)
|
|
//*-----------------------------------------------------------------------
|
|
//| Test Case: TCAccessorOnAlteredTable - Test to test the validity of accessors once rowset is modified.
|
|
//| Created: 08/05/96
|
|
//*-----------------------------------------------------------------------
|
|
|
|
//--------------------------------------------------------------------
|
|
// @mfunc TestCase Initialization Routine
|
|
//
|
|
// @rdesc TRUE or FALSE
|
|
//
|
|
BOOL TCAccessorOnAlteredTable::Init()
|
|
{
|
|
|
|
BOOL fSucceed = FALSE;
|
|
BOOL fProc = FALSE; // Whether we're using procs or views to cause columns changed
|
|
ULONG i;
|
|
DBLENGTH ulOffset = 0;
|
|
HROW *hRowPtr = NULL;
|
|
ICommandText *pIAlterCommandText = NULL;
|
|
DBCOUNTITEM cRowsObtained;
|
|
HROW rghRows[1];
|
|
HROW * prghRows=rghRows;
|
|
CCol TempCol;
|
|
WCHAR * pwszCol1 = NULL;
|
|
WCHAR * pwszCol2 = NULL;
|
|
DBTYPE wtype1, wtype2;
|
|
DBLENGTH ulPrec1, ulPrec2;
|
|
WCHAR wszSQL[1000];
|
|
WCHAR * pwszColList = NULL;
|
|
|
|
// Initialize class variables.CLASS VARIABLES
|
|
m_pATICommandText = NULL;
|
|
m_pATIRowset = NULL;
|
|
m_pIColumnsRowsetInfo = NULL;
|
|
m_pATIColumnsInfo = NULL;
|
|
m_pATIAccessor = NULL;
|
|
m_pATIColumnsRowset = NULL;
|
|
m_cbRowSize = 0 ; // Some safe size.
|
|
m_cATDbBindings = 2;
|
|
m_hATAccessor = DB_NULL_HACCESSOR;
|
|
m_cColumnsInfo = 0;
|
|
m_rgColumnsInfo = NULL;
|
|
m_pStringsBuffer = NULL;
|
|
m_cColumnsRowsetInfoObtained = 0;
|
|
m_rgColumnsRowsetInfohRows[3]; // 2 hrows for Now One for Later (after alter table).
|
|
m_pwszObjName = NULL;
|
|
|
|
|
|
// {{ TCW_INIT_BASECLASS_CHECK
|
|
if(CAccessor::Init())
|
|
// }}
|
|
{
|
|
//command is not supported
|
|
if(!m_pIDBCreateCommand)
|
|
{
|
|
odtLog << wszCommandNotSupported;
|
|
return TEST_SKIPPED;
|
|
}
|
|
|
|
// Create the command objects
|
|
if(!CHECK(m_pIDBCreateCommand->CreateCommand(NULL, IID_ICommandText, (IUnknown **)&m_pATICommandText), S_OK))
|
|
goto CLEANUP;
|
|
|
|
// Create a unique view or proc name (object name) rather than a "hard-coded" one. Make it the
|
|
// same length as the table name.
|
|
m_pwszObjName = MakeObjectName(L"IAccObj", wcslen(m_pTable->GetTableName()));
|
|
|
|
if (!m_pwszObjName)
|
|
goto CLEANUP;
|
|
|
|
// Go through the columns of the table and find two with different data types.
|
|
for (ULONG iCol=1; iCol<=m_pTable->CountColumnsOnTable() && !pwszCol2; iCol++)
|
|
{
|
|
CHECK(m_pTable->GetColInfo(iCol, TempCol), S_OK);
|
|
|
|
if (iCol == 1)
|
|
{
|
|
wtype1 = TempCol.GetProviderType();
|
|
ulPrec1 = TempCol.GetMaxSize();
|
|
if (wtype1 == DBTYPE_STR)
|
|
ulPrec1+=sizeof(CHAR); // Allow for null terminator
|
|
if (wtype1 == DBTYPE_WSTR)
|
|
ulPrec1+=sizeof(WCHAR); // Allow for null terminator
|
|
pwszCol1 = wcsDuplicate(TempCol.GetColName());
|
|
m_rgColMap[0] = iCol;
|
|
}
|
|
else if (TempCol.GetProviderType() != wtype1)
|
|
{
|
|
wtype2 = TempCol.GetProviderType();
|
|
ulPrec2 = TempCol.GetMaxSize();
|
|
if (wtype2 == DBTYPE_STR)
|
|
ulPrec2+=sizeof(CHAR); // Allow for null terminator
|
|
if (wtype2 == DBTYPE_WSTR)
|
|
ulPrec2+=sizeof(WCHAR); // Allow for null terminator
|
|
pwszCol2 = wcsDuplicate(TempCol.GetColName());
|
|
m_rgColMap[1] = iCol;
|
|
}
|
|
}
|
|
|
|
if (!pwszCol2)
|
|
{
|
|
// We couldn't find two different data types in the table, skip this test
|
|
odtLog << L"This test case needs two different data types.\n";
|
|
fSucceed = TEST_SKIPPED;
|
|
goto CLEANUP;
|
|
}
|
|
|
|
// The row size is the size of each data item plus the status and length
|
|
m_cbRowSize = ulPrec1 + ulPrec2 + 2*sizeof(DBSTATUS) + 2*sizeof(DBLENGTH);
|
|
|
|
SAFE_ALLOC(pwszColList, WCHAR, wcslen(pwszCol1)+wcslen(pwszCol2)+wcslen(L", ")+sizeof(WCHAR));
|
|
swprintf(pwszColList, L"%s, %s", pwszCol1, pwszCol2);
|
|
|
|
swprintf(wszSQL, wszCREATE_VIEW, m_pwszObjName, pwszColList, m_pTable->GetTableName());
|
|
|
|
// Now try to create a view on the table in ordinal order
|
|
if (!CHECK (m_pATICommandText->SetCommandText (DBGUID_DBSQL, wszSQL), S_OK))
|
|
goto CLEANUP;
|
|
|
|
// Create the view
|
|
if (FAILED(m_pATICommandText->Execute (NULL, IID_NULL, NULL, NULL, NULL)))
|
|
{
|
|
// Create view failed, create a proc on the table in ordinal order instead
|
|
swprintf(wszSQL, wszCREATE_PROC, m_pwszObjName, pwszColList, m_pTable->GetTableName());
|
|
if (!CHECK (m_pATICommandText->SetCommandText (DBGUID_DBSQL, wszSQL), S_OK))
|
|
goto CLEANUP;
|
|
|
|
if (FAILED(m_pATICommandText->Execute (NULL, IID_NULL, NULL, NULL, NULL)))
|
|
{
|
|
// Skip test if we can't create views or procedures for some reason. Not all providers support this.
|
|
odtLog << "Can't create the view or procedure needed for this test case.\n";
|
|
fSucceed = TEST_SKIPPED;
|
|
goto CLEANUP;
|
|
}
|
|
|
|
fProc = TRUE;
|
|
}
|
|
else
|
|
m_pTable->SetViewName(m_pwszObjName);
|
|
|
|
// Now generate the rowset
|
|
if (!fProc)
|
|
{
|
|
// Select from the view
|
|
swprintf(wszSQL, wszSELECT_COLLISTFROMTBL, L"*", m_pwszObjName);
|
|
}
|
|
else
|
|
{
|
|
// {call procname}
|
|
swprintf(wszSQL, wszEXEC_PROC, m_pwszObjName);
|
|
}
|
|
|
|
if (!CHECK (m_pATICommandText->SetCommandText (DBGUID_DBSQL, wszSQL), S_OK))
|
|
goto CLEANUP;
|
|
|
|
if (!CHECK (m_pATICommandText->Execute(NULL, IID_IRowset, NULL, NULL, (IUnknown **)&m_pATIRowset), S_OK))
|
|
goto CLEANUP;
|
|
|
|
// Now we have the rowset
|
|
// Lets create the accessor;
|
|
if (!VerifyInterface(m_pATIRowset, IID_IAccessor,
|
|
ROWSET_INTERFACE,(IUnknown **)&m_pATIAccessor))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
|
|
// Verify other properties.
|
|
if (!VerifyInterface(m_pATIRowset, IID_IColumnsInfo,
|
|
ROWSET_INTERFACE,(IUnknown **)&m_pATIColumnsInfo))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
|
|
// Create the bindings and the create handle to accessor.
|
|
for (i = 0; i < m_cATDbBindings; i++ )
|
|
{
|
|
m_rgATDbBindings[i].dwPart = DBPART_VALUE | DBPART_LENGTH | DBPART_STATUS;
|
|
m_rgATDbBindings[i].eParamIO = DBPARAMIO_NOTPARAM;
|
|
m_rgATDbBindings[i].iOrdinal = i+1;
|
|
m_rgATDbBindings[i].pTypeInfo = NULL;
|
|
|
|
m_rgATDbBindings[i].dwMemOwner = DBMEMOWNER_CLIENTOWNED;
|
|
m_rgATDbBindings[i].pBindExt = NULL;
|
|
m_rgATDbBindings[i].bPrecision = 0;
|
|
m_rgATDbBindings[i].bScale = 0;
|
|
}
|
|
|
|
// Set Binding values of individual members
|
|
// For data type 1
|
|
m_rgATDbBindings[0].obValue = offsetof (DATA, bValue);
|
|
m_rgATDbBindings[0].obLength = offsetof (DATA, ulLength);
|
|
m_rgATDbBindings[0].obStatus = offsetof (DATA, sStatus);
|
|
m_rgATDbBindings[0].cbMaxLen = ulPrec1;
|
|
m_rgATDbBindings[0].wType = wtype1;
|
|
m_rgATDbBindings[0].dwFlags = 0;
|
|
|
|
ulOffset = sizeof (DATA) + ulPrec1;
|
|
ulOffset = ROUND_UP(ulOffset, ROUND_UP_AMOUNT);
|
|
|
|
// For data type 2
|
|
m_rgATDbBindings[1].obValue = ulOffset + offsetof (DATA, bValue);
|
|
m_rgATDbBindings[1].obLength = ulOffset + offsetof (DATA, ulLength);
|
|
m_rgATDbBindings[1].obStatus = ulOffset + offsetof (DATA, sStatus);
|
|
m_rgATDbBindings[1].cbMaxLen = ulPrec2;
|
|
m_rgATDbBindings[1].wType = wtype2;
|
|
m_rgATDbBindings[1].dwFlags = 0;
|
|
|
|
ulOffset+=sizeof (DATA) + ulPrec2;
|
|
ulOffset = ROUND_UP(ulOffset, ROUND_UP_AMOUNT);
|
|
|
|
m_cbRowSize = ulOffset;
|
|
|
|
// Call create accessor.
|
|
if (!CHECK (m_pATIAccessor->CreateAccessor(
|
|
DBACCESSOR_ROWDATA, m_cATDbBindings, m_rgATDbBindings, m_cbRowSize,
|
|
&m_hATAccessor, NULL), S_OK))
|
|
{
|
|
|
|
goto CLEANUP;
|
|
}
|
|
|
|
if (!CHECK (m_pATIColumnsInfo->GetColumnInfo ( &m_cColumnsInfo, &m_rgColumnsInfo, &m_pStringsBuffer), S_OK))
|
|
goto CLEANUP;
|
|
|
|
// We have to retrieve data before DB_S_COLUMNSCHANGED will be returned.
|
|
if (!CHECK(m_pATIRowset->GetNextRows(NULL, 0, 1, &cRowsObtained, &prghRows), S_OK))
|
|
goto CLEANUP;
|
|
|
|
if (!CHECK(m_pATIRowset->ReleaseRows(1, rghRows, NULL, NULL, NULL), S_OK))
|
|
goto CLEANUP;
|
|
|
|
if(FAILED(m_pIDBCreateCommand->CreateCommand(NULL, IID_ICommandText, (IUnknown **)&pIAlterCommandText)))
|
|
{
|
|
odtLog << "Create command Failed\n";
|
|
goto CLEANUP;
|
|
}
|
|
|
|
// Switch the order of the columns
|
|
swprintf(pwszColList, L"%s, %s", pwszCol2, pwszCol1);
|
|
|
|
// Now alter the rowset underneath
|
|
if (!fProc)
|
|
{
|
|
if (FAILED(m_pTable->ExecuteCommand(DROP_VIEW, IID_NULL, m_pwszObjName, NULL, 0, NULL,
|
|
EXECUTE_IFNOERROR)))
|
|
{
|
|
if (FAILED(m_pTable->ExecuteCommand(DROP_TABLE, IID_NULL, m_pwszObjName, NULL, 0, NULL,
|
|
EXECUTE_IFNOERROR)))
|
|
{
|
|
odtLog << L"Couldn't alter rowset while open.\n";
|
|
goto CLEANUP;
|
|
}
|
|
}
|
|
|
|
|
|
// Now create the same view on the table in reverse ordinal order
|
|
swprintf(wszSQL, wszCREATE_VIEW, m_pwszObjName, pwszColList, m_pTable->GetTableName());
|
|
if (!CHECK (pIAlterCommandText->SetCommandText (DBGUID_DBSQL, wszSQL), S_OK))
|
|
goto CLEANUP;
|
|
|
|
}
|
|
else
|
|
{
|
|
if (FAILED(m_pTable->ExecuteCommand(DROP_PROC, IID_NULL, m_pwszObjName, NULL, 0, NULL,
|
|
EXECUTE_IFNOERROR)))
|
|
{
|
|
odtLog << L"Couldn't alter rowset while open.\n";
|
|
goto CLEANUP;
|
|
}
|
|
|
|
// Now create the same proc on the table in reverse ordinal order
|
|
swprintf(wszSQL, wszCREATE_PROC, m_pwszObjName, pwszColList, m_pTable->GetTableName());
|
|
if (!CHECK (pIAlterCommandText->SetCommandText (DBGUID_DBSQL, wszSQL), S_OK))
|
|
goto CLEANUP;
|
|
|
|
}
|
|
|
|
// Create the view or proc again
|
|
if (!CHECK (pIAlterCommandText->Execute (NULL, IID_NULL, NULL, NULL, NULL), S_OK ))
|
|
goto CLEANUP;
|
|
|
|
|
|
fSucceed = TRUE;
|
|
}
|
|
|
|
|
|
CLEANUP:
|
|
|
|
SAFE_FREE(pwszCol1);
|
|
SAFE_FREE(pwszCol2);
|
|
SAFE_FREE(pwszColList);
|
|
|
|
SAFE_RELEASE(pIAlterCommandText);
|
|
|
|
return fSucceed;
|
|
}
|
|
|
|
|
|
// {{ TCW_VAR_PROTOTYPE(1)
|
|
//*-----------------------------------------------------------------------
|
|
// @mfunc Test to verify the validity of accessors on an altered rowset.
|
|
//
|
|
// @rdesc TEST_PASS or TEST_FAIL
|
|
//
|
|
int TCAccessorOnAlteredTable::Variation_1()
|
|
{
|
|
DBCOUNTITEM cRowsObtained;
|
|
HROW * phRow = NULL;
|
|
BYTE * pData=NULL;
|
|
BOOL fSuccess = FALSE;
|
|
HACCESSOR hAccessor = DB_NULL_HACCESSOR;
|
|
DBORDINAL ulTemp;
|
|
HRESULT hrRestart = E_FAIL;
|
|
|
|
// Call RestartPosition and Get DB_S_COLUMNSCHANGED.
|
|
hrRestart = m_pATIRowset->RestartPosition(NULL);
|
|
|
|
if (FAILED(hrRestart))
|
|
{
|
|
// This will always return E_FAIL on Kagers; Kagera can't return DB_S_COLUMNSCHANGED
|
|
TESTC_(hrRestart, DB_S_COLUMNSCHANGED);
|
|
}
|
|
|
|
// Allocate space for data buffer
|
|
SAFE_ALLOC(pData, BYTE, m_cbRowSize);
|
|
memset(pData, 0, (size_t)m_cbRowSize);
|
|
|
|
// If the columns changed we have to rebuild the accessor to set the ordinals oppositely
|
|
if (hrRestart == DB_S_COLUMNSCHANGED)
|
|
{
|
|
// Since we changed the column ordering it's the consumer's responsibility to
|
|
// correctly modify the accessor.
|
|
ulTemp = m_rgColMap[0];
|
|
m_rgColMap[0] = m_rgColMap[1];
|
|
m_rgColMap[1] = ulTemp;
|
|
|
|
ulTemp = m_rgATDbBindings[0].iOrdinal;
|
|
m_rgATDbBindings[0].iOrdinal = m_rgATDbBindings[1].iOrdinal;
|
|
m_rgATDbBindings[1].iOrdinal = ulTemp;
|
|
}
|
|
|
|
// Now create the accessor
|
|
TESTC_(m_pATIAccessor->CreateAccessor(DBACCESSOR_ROWDATA, m_cATDbBindings, m_rgATDbBindings, m_cbRowSize,
|
|
&hAccessor, NULL), S_OK);
|
|
|
|
// Call GetNextRows to fetch the first row
|
|
TESTC_(m_pATIRowset->GetNextRows(NULL,0,1,&cRowsObtained, &phRow), S_OK);
|
|
|
|
// Call GetData to retrieve the data valuus
|
|
TESTC_(m_pATIRowset->GetData(*phRow, hAccessor, pData), S_OK);
|
|
|
|
//Verify data value, length and status are what is expected
|
|
TESTC(CompareData(m_cATDbBindings, m_rgColMap, 1, pData, m_cATDbBindings, m_rgATDbBindings,
|
|
m_pTable, m_pIMalloc, PRIMARY));
|
|
|
|
fSuccess=TRUE;
|
|
|
|
CLEANUP:
|
|
|
|
SAFE_RELEASE_ACCESSOR(m_pATIAccessor, hAccessor);
|
|
|
|
if (m_pATIRowset && phRow)
|
|
m_pATIRowset->ReleaseRows(1, phRow, NULL, NULL, NULL);
|
|
|
|
SAFE_RELEASE(m_pATIRowset);
|
|
PROVIDER_FREE(pData);
|
|
PROVIDER_FREE(phRow);
|
|
|
|
return (fSuccess) ? TEST_PASS : TEST_FAIL;
|
|
}
|
|
// }}
|
|
|
|
|
|
// {{ TCW_TERMINATE_METHOD
|
|
//--------------------------------------------------------------------
|
|
// @mfunc TestCase Termination Routine
|
|
//
|
|
// @rdesc TRUE or FALSE
|
|
//
|
|
BOOL TCAccessorOnAlteredTable::Terminate()
|
|
{
|
|
SAFE_RELEASE(m_pATIColumnsInfo);
|
|
SAFE_RELEASE(m_pATIAccessor );
|
|
PROVIDER_FREE(m_pStringsBuffer);
|
|
PROVIDER_FREE(m_rgColumnsInfo );
|
|
|
|
if (m_pIColumnsRowsetInfo && m_cColumnsRowsetInfoObtained > 0)
|
|
m_pIColumnsRowsetInfo->ReleaseRows(m_cColumnsRowsetInfoObtained, m_rgColumnsRowsetInfohRows,
|
|
NULL, NULL, NULL);
|
|
|
|
SAFE_RELEASE(m_pIColumnsRowsetInfo);
|
|
|
|
// Try to drop the view with both "drop view" and "drop table" syntax. We don't check the return
|
|
// code because Terminate will be called even if the creation in init failed.
|
|
if (m_pATICommandText && m_pwszObjName && FAILED(m_pTable->ExecuteCommand(DROP_VIEW, IID_NULL, m_pwszObjName,
|
|
NULL, 0, NULL, EXECUTE_IFNOERROR)))
|
|
{
|
|
// Some providers use "Drop Table" syntax to drop a view
|
|
if (FAILED(m_pTable->ExecuteCommand(DROP_TABLE, IID_NULL, m_pwszObjName, NULL, 0, NULL, EXECUTE_IFNOERROR)))
|
|
{
|
|
// If views aren't supported we may use procedures
|
|
m_pTable->ExecuteCommand(DROP_PROC, IID_NULL, m_pwszObjName, NULL, 0, NULL, EXECUTE_IFNOERROR);
|
|
}
|
|
}
|
|
|
|
if (m_pATIAccessor)
|
|
m_pATIAccessor->ReleaseAccessor (m_hATAccessor, NULL);
|
|
|
|
SAFE_FREE(m_pwszObjName);
|
|
SAFE_RELEASE(m_pATIColumnsRowset);
|
|
SAFE_RELEASE(m_pATIColumnsInfo);
|
|
SAFE_RELEASE(m_pATIAccessor );
|
|
SAFE_RELEASE(m_pATICommandText);
|
|
|
|
// {{ TCW_TERM_BASECLASS_CHECK2
|
|
return(CAccessor::Terminate());
|
|
} // }}
|
|
// }}
|
|
// }}
|