2025-11-28 00:35:46 +09:00

8079 lines
222 KiB
C++

//--------------------------------------------------------------------
// Microsoft OLE DB Test
//
// Copyright 1995-2000 Microsoft Corporation.
//
// @doc
//
// @module multres.cpp | Source file for all IMultipleResults.
//
//--------------------------------------------------------------------
#include "modstandard.hpp"
#include "imultres.h"
#include "ExtraLib.h"
// Define our static data members
IMalloc * CMultResults::s_pIMalloc = NULL; // Task memory allocator
DBORDINAL * CMultResults::s_rgParamOrdinals = NULL; // Array of parameter ordinals
BOOL g_fKagera=FALSE;
BOOL g_fSQLOLEDB=FALSE;
BOOL g_fRowSupp=TRUE;
BOOL g_bMultipleParamSets = FALSE;
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Module Values
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// {{ TCW_MODULE_GLOBALS
DECLARE_MODULE_CLSID = { 0x27e72d20, 0x128b, 0x11d0, { 0xba, 0x46, 0x00, 0xa0, 0xc9, 0x0d, 0x80, 0x78 }};
DECLARE_MODULE_NAME("IMultipleResults");
DECLARE_MODULE_OWNER("Microsoft");
DECLARE_MODULE_DESCRIP("Test Module for IMultipleResults");
DECLARE_MODULE_VERSION(795921705);
// TCW_WizardVersion(2)
// TCW_Automation(True)
// }} TCW_MODULE_GLOBALS_END
//--------------------------------------------------------------------
// @func Module level initialization routine
//
// @rdesc Success or Failure
// @flag TRUE | Successful initialization
// @flag FALSE | Initialization problems
//
BOOL ModuleInit(CThisTestModule * pThisTestModule)
{
BOOL fResults = FALSE;
ULONG_PTR ulValue;
ULONG i;
LPWSTR wszProviderName=NULL;
IDBCreateCommand * pIDBCreateCommand=NULL;
ICommandText * pICommandText=NULL;
IMultipleResults * pIMultipleResults=NULL;
WCHAR * pwszSQLText=NULL;
g_bMultipleParamSets = FALSE;
// Initialize our static members in CMultResults. These
// can now be used everywhere in this file
if (FAILED(CoGetMalloc(1, &CMultResults::s_pIMalloc)))
return FALSE;
CMultResults::s_rgParamOrdinals =
(DBORDINAL *)CMultResults::s_pIMalloc->Alloc(MAX_PARAM_NUM * sizeof(DBORDINAL));
if (!CMultResults::s_rgParamOrdinals)
goto CLEANUP;
// For the elements of the array, put
// consecutive ordinals, beginning with 1
for (i=0; i<MAX_PARAM_NUM; i++)
CMultResults::s_rgParamOrdinals[i] = i+1;
// Make sure we support IMultipleResults or stop immediately
if (ModuleCreateDBSession(pThisTestModule))
{
if (!((GetProperty(DBPROP_MULTIPLERESULTS, DBPROPSET_DATASOURCEINFO, pThisTestModule->m_pIUnknown, &ulValue)) &&
(ulValue != DBPROPVAL_MR_NOTSUPPORTED)))
{
CTable CTestTable((IUnknown *)pThisTestModule->m_pIUnknown2,(LPWSTR)gwszModuleName);
odtLog<<L"IMultipleResults not supported by the Provider."<<ENDL;
fResults = TEST_SKIPPED;
// If the property claims no support then try to get the interface. We'd better get E_NOINTERFACE.
// We have to have commands in order to do this
if (!VerifyInterface(pThisTestModule->m_pIUnknown2, IID_IDBCreateCommand,SESSION_INTERFACE,
(IUnknown **)&pIDBCreateCommand))
goto CLEANUP;
// Unfortunately we need a table to try this also
if (FAILED(CTestTable.CreateTable(0)))
{
fResults=FALSE;
goto CLEANUP;
}
if (SUCCEEDED(pIDBCreateCommand->CreateCommand(NULL, IID_ICommandText,(IUnknown **)&pICommandText)))
{
CTestTable.CreateSQLStmt(SELECT_ALLFROMTBL,NULL,
&pwszSQLText,NULL,NULL);
if (CHECK(pICommandText->SetCommandText(DBGUID_DBSQL, pwszSQLText), S_OK))
{
// Execute requesting IMultipleResults interface should return E_NOINTERFACE
HRESULT hr = pICommandText->Execute(NULL, IID_IMultipleResults, NULL, NULL, (IUnknown **)&pIMultipleResults);
TESTC_(hr,E_NOINTERFACE);
}
}
CTestTable.DropTable();
PROVIDER_FREE(pwszSQLText);
goto CLEANUP;
}
if(GetModInfo()->GetFileName())
{
odtLog << L"INFO: Test does not support using fixed table from ini file, resetting...\n";
GetModInfo()->ResetIniFile();
}
if (GetModInfo()->GetInsert() == INSERT_ROWSETCHANGE)
{
odtLog << L"INFO: Test does not support using INSERT_ROWSETCHANGE, resetting to INSERT_COMMAND\n";
GetModInfo()->SetInsert(INSERT_COMMAND);
}
g_fKagera=FALSE;
g_fSQLOLEDB=FALSE;
if (GetProperty(DBPROP_PROVIDERNAME, DBPROPSET_DATASOURCEINFO, pThisTestModule->m_pIUnknown, &wszProviderName)
&& wszProviderName)
{
if (!wcscmp((LPWSTR)wszProviderName, L"MSDASQL.DLL"))
g_fKagera=TRUE;
if (!wcscmp((LPWSTR)wszProviderName, L"sqloledb.dll"))
g_fSQLOLEDB=TRUE;
}
PROVIDER_FREE(wszProviderName);
// Get multiple paramsets support
g_bMultipleParamSets = GetProperty(DBPROP_MULTIPLEPARAMSETS,
DBPROPSET_DATASOURCEINFO, pThisTestModule->m_pIUnknown, VARIANT_TRUE);
fResults=TRUE;
}
CLEANUP:
SAFE_RELEASE(pICommandText);
SAFE_RELEASE(pIMultipleResults);
SAFE_RELEASE(pIDBCreateCommand);
return fResults;
}
//--------------------------------------------------------------------
// @func Module level termination routine
//
// @rdesc Success or Failure
// @flag TRUE | Successful initialization
// @flag FALSE | Initialization problems
//
BOOL ModuleTerminate(CThisTestModule * pThisTestModule)
{
// Release our static data members
if (CMultResults::s_pIMalloc)
{
if (CMultResults::s_rgParamOrdinals)
CMultResults::s_pIMalloc->Free(CMultResults::s_rgParamOrdinals);
CMultResults::s_pIMalloc->Release();
CMultResults::s_pIMalloc = NULL;
}
if (ModuleReleaseDBSession(pThisTestModule))
return TRUE;
else
return FALSE;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Helper functions
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
BOOL IsServerCursorProperty(DBPROPID dwPropID)
{
switch(dwPropID)
{
case DBPROP_IRowsetChange:
case DBPROP_IRowsetFind:
case DBPROP_IRowsetLocate:
case DBPROP_IRowsetResynch:
case DBPROP_IRowsetRefresh:
case DBPROP_IRowsetUpdate:
case DBPROP_IRowsetScroll:
case DBPROP_IDBAsynchStatus:
return TRUE;
break;
default:
return FALSE;
}
}
BOOL IsRowset(REFIID riid, DBRESULTFLAG lFlag)
{
BOOL fRet = TRUE;
BOOL fRowsetIID = FALSE;
BOOL fRowIID = FALSE;
if(lFlag == DBRESULTFLAG_ROW)
fRet = FALSE;
if((lFlag == DBRESULTFLAG_DEFAULT) && !(IsIIDThisType(riid, ROWSET_INTERFACE)))
fRet = FALSE;
return fRet;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Base class declarations
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
//////////////////////////////////////////////////////////////////
// CTestBase
//////////////////////////////////////////////////////////////////
// CTestBase::Init --------------------------------------------
//
// Initialization
//
//
BOOL CTestBase::Init()
{
BOOL fResults = FALSE;
ULONG_PTR ulVal = 0;
ULONG i;
m_pSelectTable = NULL;
m_pChangeTable = NULL;
m_cSelectTableRows = 0;
///////////////////////////////////////////////////////////////
//Get a command object and set our ICommandText pointer to it.
//Note that we create the DBSession in ModuleInit, and here call
//IDBCreateCommand explicitly (rather than CreateCommandObject)
//so we don't force a CreateTable call in CreateCommandObject,
//since we won't use the CTable in that object.
///////////////////////////////////////////////////////////////
SetDBSession((IDBCreateCommand *)m_pThisTestModule->m_pIUnknown2);
if(!GetProperty(DBPROP_OLEOBJECTS, DBPROPSET_DATASOURCEINFO,
GetModInfo()->GetThisTestModule()->m_pIUnknown, &ulVal) ||
!(ulVal & DBPROPVAL_OO_SINGLETON))
{
g_fRowSupp = FALSE;
if(ISROW)
{
odtLog<<L"INFO: Getting ROW objects thru IMultipleResults::GetResult is not supported.\n";
return TEST_SKIPPED;
}
}
//Make sure that setting the session yielded us an IDBCreateCommand,
//otherwise commands aren't supported and we can't go on
if (m_pIDBCreateCommand)
{
if (!CHECK(m_pIDBCreateCommand->CreateCommand(NULL, IID_ICommandText,
(IUnknown **)&m_pICommandText), S_OK))
goto END;
}
else
{
odtLog << L"Commands not supported, testcase will not be executed.\n";
goto END;
}
// Hack for Kagera. We have to force the insert to use commands otherwise we
// end up getting into QBU mode which can't insert BLOB columns.
if (!GetModInfo()->GetInsert())
GetModInfo()->SetInsert(INSERT_COMMAND);
//////////////////////////////////////////////////////
//Create tables to be used by all objects in our vars
//We own these and must delete them in Terminate
//////////////////////////////////////////////////////
m_pChangeTable = new CTable(m_pIDBCreateCommand,(LPWSTR)gwszModuleName, NONULLS);
if (!m_pChangeTable)
goto END;
m_pSelectTable = new CTable(m_pIDBCreateCommand,(LPWSTR)gwszModuleName, NONULLS);
if (!m_pSelectTable)
goto END;
// Create the table with index so we can obtain support IRowsetLocate on Sql server
if(m_pSelectTable->CreateTable(0) != S_OK)
goto END;
// Make sure we have a minimum number of rows and enough rows to fill a diagonal of nulls
m_cSelectTableRows = __max(m_pSelectTable->CountColumnsOnTable(), SELECT_ROW_NUM);
// Create the table with no index so we can insert duplicate rows
if(m_pChangeTable->CreateTable(0, 0) != S_OK)
goto END;
//Put in all rows based on seed ROW_SEED for our select table
for (i=0; i<m_cSelectTableRows; i++)
{
if (!CHECK(m_pSelectTable->Insert(ROW_SEED+i), S_OK))
goto END;
}
// Note: MakeData creates different data for an index column than
// for a non-index column. Since we need the data to match between
// the tables we'll find out what the index column of the first
// table is and lie to CTable by telling it we have an index on the
// second table that matches. Therefore it will make identical data.
m_pChangeTable->SetIndexColumn(m_pSelectTable->GetIndexColumn());
//Put in all rows based on seed ROW_SEED for our Change table
//NOTE: m_cRowsInSelectTable is assigned to CHANGE_ROW_NUM
//in our constructor, so if this code is changed, change
//m_cRowsInSelectTable accordingly. We need to assign
//the value in the CTOR so it is available to the
//derived class's FInit before it defers to this base class FInit.
for (i=0; i<CHANGE_ROW_NUM; i++)
{
// Force insert
if (!CHECK(m_pChangeTable->Insert(ROW_SEED), S_OK))
goto END;
}
//This is a total hack to force SQL Server into firehose mode,
//the only mode in which batched statements are allowed. We
//must make sure there is only one command active per session,
//so we will keep the command passed to our constructor, but
//release the ones associated with our CTable objects. Note
//this will totally disable command functionality on the CTable
//objects we have, so we must always do the command functionality
//ourselves.
if (m_pChangeTable->get_ICommandPTR())
{
m_pChangeTable->get_ICommandPTR()->Release();
m_pChangeTable->set_ICommandPTR(NULL);
}
if (m_pSelectTable->get_ICommandPTR())
{
m_pSelectTable->get_ICommandPTR()->Release();
m_pSelectTable->set_ICommandPTR(NULL);
}
fResults = TRUE;
END:
return fResults;
}
// CTestBase::SetRowsetPropertyDefault ------------------------------------
//
// Sets the given rowset property using ICommandProperties to the default value
//
//
HRESULT CTestBase::SetRowsetPropertyDefault(DBPROPID DBPropID)
{
ICommandProperties * pICmdProps = NULL;
DBPROPSET DBPropSet;
DBPROP DBProp;
ASSERT(m_pICommandText);
m_hr = E_FAIL;
//Set up the rowset property structure to use the ID passed in
DBPropSet.rgProperties = &DBProp;
DBPropSet.cProperties = 1;
DBPropSet.guidPropertySet = DBPROPSET_ROWSET;
DBProp.dwPropertyID = DBPropID;
DBProp.dwOptions = DBPROPOPTIONS_OPTIONAL;
DBProp.colid = DB_NULLID;
DBProp.vValue.vt = VT_EMPTY; //Causes default to be set
if (CHECK(m_hr = m_pICommandText->QueryInterface(IID_ICommandProperties,
(void **)&pICmdProps), S_OK))
{
m_hr = pICmdProps->SetProperties(1, &DBPropSet);
if (SUCCEEDED(m_hr))
//Check that it went OK. We won't increment error count if it
//fails since it may just not be supported, in which case we
//return FALSE
if (DBProp.dwStatus != DBPROPSTATUS_OK)
m_hr = E_FAIL;
pICmdProps->Release();
}
return m_hr;
}
// CTestBase::SetRowsetPropertyOn ------------------------------------
//
// Sets the given rowset property using ICommandProperties to VARIANT_TRUE
//
//
HRESULT CTestBase::SetRowsetPropertyOn(DBPROPID DBPropID, VARTYPE vt, void * pValue)
{
ICommandProperties * pICmdProps = NULL;
DBPROPSET DBPropSet;
DBPROP DBProp;
ASSERT(m_pICommandText);
m_hr = E_FAIL;
//Set up the rowset property structure to use the ID passed in
DBPropSet.rgProperties = &DBProp;
DBPropSet.cProperties = 1;
DBPropSet.guidPropertySet = DBPROPSET_ROWSET;
DBProp.dwPropertyID = DBPropID;
DBProp.dwOptions = DBPROPOPTIONS_REQUIRED;
DBProp.colid = DB_NULLID;
DBProp.dwStatus = DBPROPSTATUS_OK;
DBProp.vValue.vt = vt;
switch(vt)
{
case VT_BOOL:
V_BOOL(&(DBProp.vValue)) = (VARIANT_BOOL)pValue; //Turn property on
break;
case VT_I4:
V_I4(&(DBProp.vValue)) = (LONG)(LONG_PTR)pValue;
break;
default:
odtLog << L"Unknown property type.\n";
CHECK(0, 1);
}
if (CHECK(m_hr = m_pICommandText->QueryInterface(IID_ICommandProperties,
(void **)&pICmdProps), S_OK))
{
m_hr = pICmdProps->SetProperties(1, &DBPropSet);
if (SUCCEEDED(m_hr))
//Check that it went OK. We won't increment error count if it
//fails since it may just not be supported, in which case we
//return FALSE
if (DBProp.dwStatus == DBPROPSTATUS_OK)
m_hr = NOERROR;
pICmdProps->Release();
}
return m_hr;
}
// CTestBase::TryLocate ------------------------------------
//
//Uses IRowsetLocate to ensure it is functional on this rowset
//
//
HRESULT CTestBase::TryLocate(IRowsetLocate * pIRowLoc)
{
DBBOOKMARK Bkmk = DBBMK_FIRST;
DBCOUNTITEM cRowsObtained = 0;
HROW hRow1 = DB_NULL_HROW;
HROW * phRow1 = &hRow1;
HROW hRow2 = DB_NULL_HROW;
HROW * phRow2 = &hRow2;
DBBINDING * rgBindings = NULL;
DBCOUNTITEM cBindings = 0;
DBLENGTH cbRowSize = 0;
HACCESSOR hAccessor = DB_NULL_HACCESSOR;
IAccessor * pIAccessor = NULL;
BYTE * pData1 = NULL;
BYTE * pData2 = NULL;
m_hr = NOERROR;
if (!CHECK(m_hr = pIRowLoc->QueryInterface(IID_IAccessor,
(void **)&pIAccessor),
S_OK))
goto CLEANUP;
//Create an accessor
if (S_OK != (m_hr = GetAccessorAndBindings(pIRowLoc,
DBACCESSOR_ROWDATA,
&hAccessor,
&rgBindings,
&cBindings,
&cbRowSize)))
goto CLEANUP;
//Allocate a new data buffers
pData1 = (BYTE *)CMultResults::s_pIMalloc->Alloc(cbRowSize);
if (!pData1)
{
m_hr = ResultFromScode(E_OUTOFMEMORY);
goto CLEANUP;
}
pData2 = (BYTE *)CMultResults::s_pIMalloc->Alloc(cbRowSize);
if (!pData2)
{
m_hr = ResultFromScode(E_OUTOFMEMORY);
goto CLEANUP;
}
memset(pData1, 0, (size_t)cbRowSize);
memset(pData2, 0, (size_t)cbRowSize);
////////////////////////////////////////////////
//Get first row with GetNextRows for comparison
////////////////////////////////////////////////
if (!CHECK(m_hr = pIRowLoc->GetNextRows(NULL,
0,
1,
&cRowsObtained,
&phRow1),
S_OK))
goto CLEANUP;
if (!CHECK(m_hr = pIRowLoc->GetData(hRow1,
hAccessor,
pData1),
S_OK))
goto CLEANUP;
CHECK(pIRowLoc->ReleaseRows(1,
&hRow1,
NULL,
NULL,
NULL),
S_OK);
hRow1 = DB_NULL_HROW;
////////////////////////////////////////////////
//Now get the same row with GetRowsAt
////////////////////////////////////////////////
if (!CHECK(m_hr = pIRowLoc->GetRowsAt(0,
0,
sizeof(DBBOOKMARK),
(BYTE *)&Bkmk,
0,
1,
&cRowsObtained,
&phRow2),
S_OK))
goto CLEANUP;
if (!CHECK(m_hr = pIRowLoc->GetData(hRow2,
hAccessor,
pData2),
S_OK))
goto CLEANUP;
CHECK(pIRowLoc->ReleaseRows(1,
&hRow2,
NULL,
NULL,
NULL),
S_OK);
hRow2 = DB_NULL_HROW;
////////////////////////////////////////////////
// Compare the two, should be the same row
////////////////////////////////////////////////
if (!COMPARE(memcmp(pData1, pData2, (size_t)cbRowSize), 0))
m_hr = E_FAIL;
CLEANUP:
if (pIAccessor)
{
pIAccessor->ReleaseAccessor(hAccessor, NULL);
pIAccessor->Release();
}
if (rgBindings)
CMultResults::s_pIMalloc->Free(rgBindings);
if (pData1)
CMultResults::s_pIMalloc->Free(pData1);
if (pData2)
CMultResults::s_pIMalloc->Free(pData2);
if (hRow1 != DB_NULL_HROW)
pIRowLoc->ReleaseRows(1,
&hRow1,
NULL,
NULL,
NULL);
if (hRow2 != DB_NULL_HROW)
pIRowLoc->ReleaseRows(1,
&hRow2,
NULL,
NULL,
NULL);
return m_hr;
}
// CTestBase::TryHoldRows ------------------------------------
//
// Ensures CANHOLDROWS works on this rowset
//
//
HRESULT CTestBase::TryHoldRows(IRowset * pIRowset)
{
DBCOUNTITEM cRowsObtained = 0;
HROW hRow1 = DB_NULL_HROW;
HROW * phRow1 = &hRow1;
HROW hRow2 = DB_NULL_HROW;
HROW * phRow2 = &hRow2;
DBBINDING * rgBindings = NULL;
DBCOUNTITEM cBindings = 0;
DBLENGTH cbRowSize = 0;
HACCESSOR hAccessor = DB_NULL_HACCESSOR;
IAccessor * pIAccessor = NULL;
BYTE * pData1 = NULL;
BYTE * pData2 = NULL;
m_hr = NOERROR;
if (!CHECK(m_hr = pIRowset->QueryInterface(IID_IAccessor,
(void **)&pIAccessor),
S_OK))
goto CLEANUP;
//Create an accessor
if (S_OK != (m_hr = GetAccessorAndBindings(pIRowset,
DBACCESSOR_ROWDATA,
&hAccessor,
&rgBindings,
&cBindings,
&cbRowSize)))
goto CLEANUP;
//Allocate a new data buffers
pData1 = (BYTE *)CMultResults::s_pIMalloc->Alloc(cbRowSize);
if (!pData1)
{
m_hr = ResultFromScode(E_OUTOFMEMORY);
goto CLEANUP;
}
pData2 = (BYTE *)CMultResults::s_pIMalloc->Alloc(cbRowSize);
if (!pData2)
{
m_hr = ResultFromScode(E_OUTOFMEMORY);
goto CLEANUP;
}
memset(pData1, 0, (size_t)cbRowSize);
memset(pData2, 0, (size_t)cbRowSize);
////////////////////////////////////////////////
//Get first row with GetNextRows for comparison
////////////////////////////////////////////////
if (!CHECK(m_hr = pIRowset->GetNextRows(NULL,
0,
1,
&cRowsObtained,
(HROW **)&phRow1),
S_OK))
goto CLEANUP;
//Hold a row
if (!CHECK(m_hr = pIRowset->GetData(hRow1,
hAccessor,
pData1),
S_OK))
goto CLEANUP;
////////////////////////////////////////////////
//Now get another row, should be no problem
//even with a held row
////////////////////////////////////////////////
if (!CHECK(m_hr = pIRowset->GetNextRows(NULL,
0,
1,
&cRowsObtained,
(HROW **)&phRow2),
S_OK))
goto CLEANUP;
if (!CHECK(m_hr = pIRowset->GetData(hRow2,
hAccessor,
pData2),
S_OK))
goto CLEANUP;
/////////////////////////////////////////////////////////
// Compare the two, data should be the same for both rows
/////////////////////////////////////////////////////////
if (!COMPARE(memcmp(pData1, pData2, (size_t)cbRowSize), 0))
m_hr = E_FAIL;
CLEANUP:
//Release all rows
if (hRow1 != DB_NULL_HROW)
CHECK(pIRowset->ReleaseRows(1,
&hRow1,
NULL,
NULL,
NULL),
S_OK);
if (hRow2 != DB_NULL_HROW)
CHECK(pIRowset->ReleaseRows(1,
&hRow2,
NULL,
NULL,
NULL),
S_OK);
if (pIAccessor)
{
pIAccessor->ReleaseAccessor(hAccessor, NULL);
pIAccessor->Release();
}
if (rgBindings)
CMultResults::s_pIMalloc->Free(rgBindings);
if (pData1)
CMultResults::s_pIMalloc->Free(pData1);
if (pData2)
CMultResults::s_pIMalloc->Free(pData2);
return m_hr;
}
// CTestBase::SetUpGetResult ------------------------------------
//
// Init's (*ppMultResult)->m_pIMultResults so it is ready to call GetResult.
// User must delete *ppMultResult unless an error is returned.
// If ceSQLStmts is 0, the user does not care what SQL statements are used,
// so this routine uses a fixed on
//
//
HRESULT CTestBase::SetUpGetResult(CMultResults ** ppMultResult,
ULONG ceSQLStmts, ESQLSTMT * rgeSQLStmts, DBRESULTFLAG* rgResFlags)
{
CBatch * pNewBatch = NULL;
BOOL fResults = FALSE;
ESQLSTMT rgFixedeSQLStmts[] = {
ESELECT,
EINSERT,
EDELETE
};
const ULONG cFixedeSQLStmts = sizeof(rgFixedeSQLStmts) / sizeof(ESQLSTMT);
DBRESULTFLAG rgFixedFlag[cFixedeSQLStmts];
for(ULONG i=0; i<cFixedeSQLStmts; i++)
{
if(m_eTestCase == TC_Rowset)
rgFixedFlag[i] = DBRESULTFLAG_DEFAULT;
else
rgFixedFlag[i] = DBRESULTFLAG_ROW;
}
m_hr = E_FAIL;
if (!ppMultResult)
return E_INVALIDARG;
//Warn user that they shouldn't be passing valid
//array if count is 0 -- we'll ignore the array
if (ceSQLStmts == 0)
if (rgeSQLStmts)
return E_INVALIDARG;
//Init parameter
*ppMultResult = NULL;
//If user doesn't specify SQL, use ours
if (ceSQLStmts == 0)
{
ceSQLStmts = cFixedeSQLStmts;
rgeSQLStmts = rgFixedeSQLStmts;
rgResFlags = rgFixedFlag;
}
pNewBatch = new CBatch(m_pIDBCreateCommand,
m_pICommandText,
m_pSelectTable,
m_pChangeTable);
if (!pNewBatch)
return E_OUTOFMEMORY;
//Initialize batch statement with the proper SQL for this variation
if (!pNewBatch->FInit(ceSQLStmts, rgeSQLStmts, rgResFlags))
goto CLEANUP;
//Make sure we start clean
pNewBatch->m_pIMultResults = NULL;
//This should put a valid interface in pNewBatch->m_pIMultResults
m_hr = pNewBatch->SetAndExecute(IID_IMultipleResults);
CLEANUP:
if (SUCCEEDED(m_hr))
{
//Return our object to user
*ppMultResult = pNewBatch;
}
else
{
if (pNewBatch)
{
delete pNewBatch;
}
}
return m_hr;
}
// CTestBase::Terminate --------------------------------------------
//
// Cleanup
//
//
BOOL CTestBase::Terminate()
{
////////////////////////////////////////////////////
//Release what we created in Init
////////////////////////////////////////////////////
if (m_pChangeTable)
{
m_pChangeTable->DropTable();
delete m_pChangeTable;
m_pChangeTable = NULL;
}
if (m_pSelectTable)
{
m_pSelectTable->DropTable();
delete m_pSelectTable;
m_pSelectTable = NULL;
}
if (m_pICommandText)
{
m_pICommandText->Release();
m_pICommandText = NULL;
}
ReleaseDBSession();
return TRUE;
}
//////////////////////////////////////////////////////////////////
// CMultResults
//////////////////////////////////////////////////////////////////
// CMultResults::CMultResults --------------------------------------------
//
// CTOR
//
//
CMultResults::CMultResults(IDBCreateCommand * pIDBCreateCommand,
ICommandText * pICommandText,
CTable * pSelectTable,
CTable * pChangeTable)
{
//Init everything
m_pwszNewTableName = NULL;
m_pICommandText = NULL;
m_pIDBCreateCommand = NULL;
m_ceSQLStmts = 0;
m_rgeSQLStmts = NULL;
m_rgResFlags = NULL;
m_rgStmtRowsAffected = NULL;
m_pIMultResults = NULL;
m_pIRowset = NULL;
m_pIRow = NULL;
m_cRowsExecuteAffected = 0;
m_cRowsGetResultAffected = 0;
m_pwszSQLStmt = NULL;
m_rgSelectOrds = NULL;
m_rgCompOrds = NULL;
m_cRowsInChgTable = 0;
m_cTotalResultsExpected = 0;
m_hr = NOERROR;
m_cRowsInSelect = 0;
//Init our string tables to all null elements
memset(m_rgpwszSQL, 0, sizeof(m_rgpwszSQL));
memset(m_prgProcInfo, 0, sizeof(m_prgProcInfo));
//Increment ref counts and hold onto pointers
m_pICommandText = pICommandText;
m_pICommandText->AddRef();
m_pIDBCreateCommand = pIDBCreateCommand;
m_pIDBCreateCommand->AddRef();
//We don't own these objects, just sharing them,
//so don't clean them up in DTOR
m_pSelectTable = pSelectTable;
m_pChangeTable = pChangeTable;
}
// CMultResults::FInit --------------------------------------------------------
//
// Performs necessary initialization for object -- must always be called
// immediately after creating object for it to function correctly
//
//
BOOL CMultResults::FInit(const ULONG cSQLStmts,
ESQLSTMT * rgSQLStmts,
DBRESULTFLAG* rgResFlags,
DBCOUNTITEM * rgStmtRowsAffected)
{
ULONG i;
//Initialize members
m_ceSQLStmts = cSQLStmts;
//Default total results is the number of statements in the batch
m_cTotalResultsExpected = cSQLStmts;
//////////////////////////////////////////////////////
//Copy to our own memory user's SQL stmt arrays
//////////////////////////////////////////////////////
m_rgeSQLStmts =
(ESQLSTMT *)CMultResults::s_pIMalloc->Alloc(cSQLStmts * sizeof(ESQLSTMT));
if (!m_rgeSQLStmts)
goto FAILED;
if(rgResFlags)
{
m_rgResFlags =
(DBRESULTFLAG *)CMultResults::s_pIMalloc->Alloc(cSQLStmts * sizeof(DBRESULTFLAG));
if (!m_rgResFlags)
goto FAILED;
}
m_rgStmtRowsAffected =
(DBROWCOUNT *)CMultResults::s_pIMalloc->Alloc(cSQLStmts * sizeof(DBROWCOUNT));
if (!m_rgStmtRowsAffected)
goto FAILED;
for (i=0; i<cSQLStmts; i++)
{
m_rgeSQLStmts[i] = rgSQLStmts[i];
if(rgResFlags)
m_rgResFlags[i] = rgResFlags[i];
m_rgStmtRowsAffected[i] = rgStmtRowsAffected[i];
}
////////////////////////////////////////////////////
//Build an array of select rowset ordinals
////////////////////////////////////////////////////
//This memory is freed in DTOR
m_rgSelectOrds =
(DB_LORDINAL *)CMultResults::s_pIMalloc->Alloc(m_pSelectTable->CountColumnsOnTable() * sizeof(DB_LORDINAL));
m_rgCompOrds =
(DB_LORDINAL *)CMultResults::s_pIMalloc->Alloc((size_t)(m_pSelectTable->CountColumnsOnTable() * sizeof(DB_LORDINAL)));
if (!m_rgSelectOrds || !m_rgCompOrds)
goto FAILED;
for (i=0; i< m_pSelectTable->CountColumnsOnTable(); i++)
{
//Fill zero based array with one based column ordinals
m_rgSelectOrds[i] = i+1;
m_rgCompOrds[i] = i+1;
}
/////////////////////////////////////////////////////////////
//Generate a table name for our Create/Drop table statements
/////////////////////////////////////////////////////////////
m_pwszNewTableName = (WCHAR *)CMultResults::s_pIMalloc->Alloc(
(wcslen(m_pChangeTable->GetTableName()) + 1) * sizeof(WCHAR));
if (!m_pwszNewTableName)
goto FAILED;
//Copy in our base name, taken from Change Table
wcscpy(m_pwszNewTableName, m_pChangeTable->GetTableName());
//Now add a suffix to make a new name, copying over last chars of
//old name so we don't need any additional memory
ASSERT(wcslen(m_pwszNewTableName) >= wcslen(wszCrtTblSuffix));
wcscpy(m_pwszNewTableName + wcslen(m_pwszNewTableName) - wcslen(wszCrtTblSuffix),
wszCrtTblSuffix);
/////////////////////////////////////////////////////////////
//Build string table containing all SQL text
/////////////////////////////////////////////////////////////
if (!BuildSQLStringTable())
goto FAILED;
return TRUE;
FAILED:
return FALSE;
}
// CMultResults::BuildSQLStringTable --------------------------------------------------------
//
// Builds SQL Strings for all of our operations which have not been
// built already, places them in m_rgpwszSQL.
//
//
BOOL CMultResults::BuildSQLStringTable()
{
//////////////////////////////////////////////////////////////////////
//Note that we created a Change table with all rows having
//the same value. Each row we insert using the SQL insert
//statement below will also insert the same row values.
//When we update, we look for that same row and update
//it to the same old values again. This is done so that
//we are guaranteed that we will always have enough rows
//in the table to update given our update clause. When
//we delete, we use row values in the delete clause which
//do not exist in the table. This is done for 2 reasons:
// 1f) We get more coverage by testing statements that affect
// 0 rows (the delete) as well as 1 row (the updates and inserts).
// 2) When we execute the delete, it doesn't wipe out all rows,
// causing the next delete to not affect the same number
// of rows as the first delete.
//////////////////////////////////////////////////////////////////////
//We are responsible for freeing all these strings in DTOR
//Set the select string
if (!m_rgpwszSQL[ESELECT])
if (FAILED(m_pSelectTable->CreateSQLStmt(
SELECT_VALIDATIONORDER,
NULL,
&m_rgpwszSQL[ESELECT],
NULL,
NULL)))
goto FAILED;
//Set the insert string, always insert same value, based on seed ROW_SEED
if (!m_rgpwszSQL[EINSERT])
if (FAILED(m_pChangeTable->Insert(
ROW_SEED,
PRIMARY,
FALSE, // Don't execute
&m_rgpwszSQL[EINSERT])))
goto FAILED;
//Set the update string, always update the value based on seed ROW_SEED,
//and update it back to the same value
if (!m_rgpwszSQL[EUPDATE])
if (FAILED(m_pChangeTable->Update(
ROW_SEED,
PRIMARY,
FALSE, //Don't Execute
&m_rgpwszSQL[EUPDATE],
TRUE))) //We want the where clause and set clause to use the same values
goto FAILED;
//Set the delete string, always use a row which isn't there so it affects 0 rows
if (!m_rgpwszSQL[EDELETE])
if (FAILED(m_pChangeTable->Delete(
ROW_SEED+1,
PRIMARY,
FALSE, //Don't exeucte
&m_rgpwszSQL[EDELETE])))
goto FAILED;
//Build and set the Create Table string
if (!m_rgpwszSQL[ECREATE])
{
m_rgpwszSQL[ECREATE] = (WCHAR *)CMultResults::s_pIMalloc->Alloc((wcslen(m_pwszNewTableName) +
wcslen(wszCrtTbl) + 1) * sizeof(WCHAR));
if (!m_rgpwszSQL[ECREATE])
goto FAILED;
swprintf(m_rgpwszSQL[ECREATE], wszCrtTbl, m_pwszNewTableName);
}
//Build and set the Drop Table string
if (!m_rgpwszSQL[EDROP])
{
m_rgpwszSQL[EDROP] = (WCHAR *)CMultResults::s_pIMalloc->Alloc((wcslen(m_pwszNewTableName) +
wcslen(wszDropTbl) + 1) * sizeof(WCHAR));
if (!m_rgpwszSQL[EDROP])
goto FAILED;
swprintf(m_rgpwszSQL[EDROP], wszDropTbl, m_pwszNewTableName);
}
if (!m_rgpwszSQL[EEMPTYSELECT])
if (FAILED(m_pSelectTable->CreateSQLStmt(
SELECT_EMPTYROWSET,
NULL,
&m_rgpwszSQL[EEMPTYSELECT],
NULL,
NULL)))
goto FAILED;
// Build the computed sum statement
if (!m_rgpwszSQL[ECOMPUTESUM])
if (FAILED(m_pSelectTable->CreateSQLStmt(
SELECT_COLLISTORDERBYCOLONECOMPUTE,
NULL,
&m_rgpwszSQL[ECOMPUTESUM],
NULL,
NULL)))
goto FAILED;
// Build the wait statement
if (!m_rgpwszSQL[ESELECTWAIT])
{
LPWSTR pwszSelectWait = NULL;
LPWSTR pwszWaitFor = L"waitfor delay '000:00:10';";
pwszSelectWait = (LPWSTR)PROVIDER_ALLOC((wcslen(pwszWaitFor)+wcslen(m_rgpwszSQL[ESELECT])+1)*sizeof(WCHAR));
if (!pwszSelectWait)
goto FAILED;
wcscpy(pwszSelectWait, pwszWaitFor);
wcscat(pwszSelectWait, m_rgpwszSQL[ESELECT]);
m_rgpwszSQL[ESELECTWAIT] = pwszSelectWait;
}
return TRUE;
FAILED:
return FALSE;
}
// CMultResults::BuildConcatSQL -------------------------------------------------
//
// Allocates and builds a concatenated SQL String for all of our operations,
// places it in m_pwszSQLStmt.
//
//
HRESULT CMultResults::BuildConcatSQL()
{
size_t cbSQLStmt = 0;
ULONG i;
////////////////////////////////////////////////////
// Allocate the buffer for the SQL Statement
// and build it. It will be formed by taking each
// statement in our array concatenated together,
// separated by a space.
////////////////////////////////////////////////////
//Free and Allocate again just to be sure we haven't had the
//number of statements changed on us since last time we allocated
if (m_pwszSQLStmt)
{
CMultResults::s_pIMalloc->Free(m_pwszSQLStmt);
m_pwszSQLStmt = NULL;
}
for (i=0; i<m_ceSQLStmts; i++)
{
//Allocate room for the SQL Stmt plus a space and a semicolon
//at end of each stmt. We put a space in to get around
//Use the current element of our ESQLSTMT array to determine
//the index of the correct SQL string in the string table array
cbSQLStmt += (wcslen(m_rgpwszSQL[m_rgeSQLStmts[i]]) + 2) * sizeof(WCHAR);
}
//Add null terminator to length
cbSQLStmt += sizeof(WCHAR);
//This is freed in DTOR, or freed and realloc'd on
//subseqent calls to this function
m_pwszSQLStmt = (WCHAR *)CMultResults::s_pIMalloc->Alloc(cbSQLStmt);
if (!m_pwszSQLStmt)
return E_OUTOFMEMORY;
memset(m_pwszSQLStmt, 0, cbSQLStmt);
//Init to empty string so concats start at beginning
m_pwszSQLStmt[0] = L'\0';
for (i=0; i<m_ceSQLStmts; i++)
{
//Concat the next statement
wcscat(m_pwszSQLStmt, m_rgpwszSQL[m_rgeSQLStmts[i]]);
if (i < m_ceSQLStmts - 1)
wcscat(m_pwszSQLStmt, L" ;");
}
return NOERROR;
}
// CMultResults::Execute ------------------------------------------------
//
// Does Execute on m_pICommandText which must already be set
//
//
HRESULT CMultResults::Execute(REFIID riid, DBPARAMS * pParams)
{
IUnknown * pIUnknown = NULL;
//Nothing special here, just execute and dump results in member vars
m_hr = m_pICommandText->Execute(NULL,
riid,
pParams,
&m_cRowsExecuteAffected,
&pIUnknown);
// If IID is IUnknown or IMultipleResults always QI for IMultRes
if ((riid == IID_IMultipleResults || riid == IID_IUnknown) &&
S_OK == m_hr && !VerifyInterface(pIUnknown, IID_IMultipleResults,
COMMAND_INTERFACE, (IUnknown **)&m_pIMultResults))
m_hr = E_NOINTERFACE;
//Put interface pointer in right member variable
if (riid == IID_IMultipleResults)
{
// Use the pIUnknown returned from the method
SAFE_RELEASE(m_pIMultResults);
m_pIMultResults = (IMultipleResults *)pIUnknown;
}
else if (riid == IID_IRowset)
{
m_pIRowset=(IRowset *)pIUnknown;
}
else if (riid == IID_IRow)
{
m_pIRow=(IRow *)pIUnknown;
}
else
// We don't use the IUnknown interface, so release it here.
SAFE_RELEASE(pIUnknown);
return m_hr;
}
// CMultResults::ProcessAllResults --------------------------------------------
//
// Verifies everything about all results remaining for this result object
// (ie, the executed ole db command object), then releases all interfaces
// received from Execute and GetResult.
//
// NOTE: riidGetResult is the iid asked for on GetResult calls, and does not
// apply to Execute.
// If cTotalResults is -1, the number of statements in the batch is used as
// the total expected number of results.
//
HRESULT CMultResults::ProcessAllResults(ULONG cResultsAlreadyProcessed,
REFIID riidExecute,
IID* rgRiidGetResult)
{
ULONG i;
IUnknown * pUnkRowset = NULL;
HRESULT hr = E_FAIL;
//This will be our return value variable
m_hr = NOERROR;
if (m_pIMultResults)
{
//Starting at index cResultsAlreadyProcessed will put
//us at the next element to be processed since the
//array is 0-based and cResultsAlreadyProcessed is 1-based
for (i=cResultsAlreadyProcessed; i<m_cTotalResultsExpected; i++)
{
if (S_OK == (m_hr = m_pIMultResults->GetResult(NULL,
m_rgResFlags[i],
rgRiidGetResult[i],
&m_cRowsGetResultAffected,
(IUnknown **)&pUnkRowset)))
{
//Check everything is correct for this result
if (!COMPARE(AreGetResultOutParamsRight(i, pUnkRowset, rgRiidGetResult[i], m_rgResFlags[i]), TRUE))
{
m_hr = E_FAIL;
odtLog << L"GetResult output params are not right for result: " << i+1 << wszNewLine;
}
}
else
{
odtLog << L"GetResult did not return S_OK for result: " << i+1 << wszNewLine;
if((!IsRowset(rgRiidGetResult[i], m_rgResFlags[i])) &&(m_rgeSQLStmts[i]==EEMPTYSELECT))
{
CHECK(m_hr, DB_E_NOTFOUND);
COMPARE(pUnkRowset, NULL);
}
else
// Post a failure
CHECK(m_hr, S_OK);
}
//Release this rowset if it exists
if (pUnkRowset)
{
pUnkRowset->Release();
pUnkRowset = NULL;
}
}
//Init to garbage so we can tell that it is cleared by this method
pUnkRowset = (IUnknown *)0x12345678;
//We should have retrieved all results already, so next should be DB_S_NORESULT
if (DB_S_NORESULT == (hr = m_pIMultResults->GetResult(NULL,
0,
rgRiidGetResult[i-1],
&m_cRowsGetResultAffected,
(IUnknown **)&pUnkRowset)))
{
//Pass an iResult of i, which means we've gone passed all
//possible results. This function will then look for
//*ppRowset = NULL and *pcRowsAffected = -1.
if (!AreGetResultOutParamsRight(i, pUnkRowset, rgRiidGetResult[i-1], 0))
m_hr = E_FAIL;
}
else
if (S_OK == m_hr)
m_hr = hr;
if(pUnkRowset && (pUnkRowset!=(IUnknown *)0x12345678))
pUnkRowset->Release();
pUnkRowset = NULL;
//Now release interface received from Execute
ReleaseIMultipleResults();
}
else
{
//Verify Execute's result matches the first result expected
if(IsIIDThisType(riidExecute, ROWSET_INTERFACE))
{
if (!AreExecuteOutParamsRight(riidExecute, m_pIRowset))
{
m_hr = E_FAIL;
odtLog << L"Execute output params are not right for first result." << wszNewLine;
}
}
else
{
if (!AreExecuteOutParamsRight(riidExecute, m_pIRow))
{
m_hr = E_FAIL;
odtLog << L"Execute output params are not right for first result." << wszNewLine;
}
}
//Now release interface received from Execute
ReleaseIRowset();
}
return m_hr;
}
// CMultResults::AreGetResultOutParamsRight --------------------------------
//
// Checks *pcRowsAffected and *ppRowset, and verifies against
// the results we are supposed to get back
//
//
BOOL CMultResults::AreGetResultOutParamsRight(ULONG iResult, IUnknown * pUnkRowset, REFIID riid, DBRESULTFLAG resFlag)
{
//If we have called GetResult for more times that we have results,
//*ppRowset must be NULL and *pcRowsAffected must be -1 and no
//further checking is necessary. This is the DB_S_NORESULT case.
if (iResult >= m_cTotalResultsExpected)
{
if (pUnkRowset == NULL &&
m_cRowsGetResultAffected == -1)
return TRUE;
else
return FALSE;
}
switch (m_rgeSQLStmts[iResult])
{
case EINSERT:
case EDELETE:
case EUPDATE:
//we can check the row count
if (IsGetResultRowsAffectedRight(iResult))
//and the rowset interface returned must be NULL
return (NULL == pUnkRowset);
break;
case ECREATE:
case EDROP:
//Row count is undefined, only check rowset is null
return (NULL == pUnkRowset);
break;
case ESELECT:
case ESELECTWAIT:
if (pUnkRowset)
return S_OK == VerifySelectRowset(riid, pUnkRowset, IsRowset(riid, resFlag));
break;
case EEMPTYSELECT:
if (pUnkRowset)
return DB_S_ENDOFROWSET == VerifySelectRowset(riid, pUnkRowset, IsRowset(riid, resFlag));
break;
default:
//Need to add more code for other enums
ASSERT(FALSE);
}
//We haven't returned through one of our successful paths,
//meaning there was an error, so return FALSE
return FALSE;
}
// CMultResults::AreExecuteOutParamsRight --------------------------------
//
// Checks *pcRowsAffected and *ppRowset, and verifies against
// the results we are supposed to get back for the first result
//
//
BOOL CMultResults::AreExecuteOutParamsRight(REFIID riid, IUnknown * pUnkRowset)
{
////////////////////////////////////////////////////
//Check everything against the first result in our set,
//that is all Execute with IID_IRowset can bring back
////////////////////////////////////////////////////
switch(m_rgeSQLStmts[0])
{
case EINSERT:
case EUPDATE:
case EDELETE:
//we can check the row count
if (IsExecuteRowsAffectedRight())
//and the rowset interface returned must be NULL
return (NULL == pUnkRowset);
break;
case ECREATE:
case EDROP:
//Row count is undefined, only check rowset is null
return (NULL == pUnkRowset);
break;
case ESELECT:
if (pUnkRowset)
return S_OK == VerifySelectRowset(riid, pUnkRowset, IsIIDThisType(riid, ROWSET_INTERFACE));
break;
case EEMPTYSELECT:
if (pUnkRowset)
return DB_S_ENDOFROWSET == VerifySelectRowset(riid, pUnkRowset, IsIIDThisType(riid, ROWSET_INTERFACE));
break;
default:
//Need more code to deal with new enums
ASSERT(FALSE);
}
//We haven't returned through one of our successful paths,
//meaning there was an error, so return FALSE
return FALSE;
}
// CMultResults::VerifySelectRowset --------------------------------
//
// Checks *pcRowsAffected and *ppRowset, and verifies against
// the results we are supposed to get back
//
//
HRESULT CMultResults::VerifySelectRowset(REFIID riid, IUnknown * pUnkRowset, BOOL fIsRowset)
{
DBCOUNTITEM cRowsObtained;
BYTE * pData = NULL;
HROW * prghRows = NULL;
HACCESSOR hAccessor = DB_NULL_HACCESSOR;
HACCESSOR* phAccessor = &hAccessor;
DBLENGTH cbRowSize = 0;
DBCOUNTITEM cBindings = 0;
DBBINDING * rgBindings = NULL;
IAccessor * pIAccessor = NULL;
ULONG i;
IRow* pIRow = NULL;
IRowset * pIRowset = NULL;
IUnknown * pIUnknown = NULL;
IUnknown * pIOwnInterface = NULL;
IColumnsInfo * pIColumnsInfo = NULL;
IConvertType * pIConvertType = NULL;
IRowsetInfo * pIRowsetInfo = NULL;
DBCOLUMNINFO * pColInfo = NULL;
WCHAR * pStringsBuffer = NULL;
ULONG cPropertySets=0;
DBPROPSET * pPropertySets = NULL;
DBORDINAL cTableCols, iBind, cTableBindings;
BLOBTYPE dwBlobType = NO_BLOB_COLS | BLOB_IID_IUNKNOWN;
BOOL fFreeMem = FALSE;
CRowObject* pCRow = NULL;
//User error if we don't have a Rowset
TESTC(pUnkRowset != NULL);
//Init this to something bad so if we fall out
//anywhere we'll return a negative return code
m_hr = E_FAIL;
cRowsObtained = 0;
if(fIsRowset)
{
TESTC(DefaultObjectTesting(pUnkRowset, ROWSET_INTERFACE))
if (FAILED(m_hr = pUnkRowset->QueryInterface(IID_IRowset, (void **)&pIRowset)))
goto CLEANUP;
if (FAILED(m_hr = pUnkRowset->QueryInterface(IID_IAccessor, (void **)&pIAccessor)))
goto CLEANUP;
if (FAILED(m_hr = pUnkRowset->QueryInterface(IID_IRowsetInfo, (void **)&pIRowsetInfo)))
goto CLEANUP;
}
else
{
TESTC(DefaultObjectTesting(pUnkRowset, ROW_INTERFACE))
if (FAILED(m_hr = pUnkRowset->QueryInterface(IID_IRow, (void **)&pIRow)))
goto CLEANUP;
}
// We can always QI for our own interface off the pointer
if (FAILED(m_hr = pUnkRowset->QueryInterface(riid, (void **)&pIOwnInterface)))
goto CLEANUP;
// We should always be able to get IUnknown
if (FAILED(m_hr = pUnkRowset->QueryInterface(IID_IUnknown, (void **)&pIUnknown)))
goto CLEANUP;
// IColumnsInfo is mandatory. It's used in GetAccessorAndBindings but it's better
// to fail here if not available.
if (FAILED(m_hr = pUnkRowset->QueryInterface(IID_IColumnsInfo, (void **)&pIColumnsInfo)))
goto CLEANUP;
// IConvertType is mandatory. It may be used in GetAccessorAndBindings but it's better
// to fail here if not available.
if (FAILED(m_hr = pUnkRowset->QueryInterface(IID_IConvertType, (void **)&pIConvertType)))
goto CLEANUP;
// Make sure the interface passed in actually works by calling a method on it.
// For IID_IRowset and IID_IAccessor we call methods always.
if (riid == IID_IUnknown)
{
IUnknown * pIUnknown = (IUnknown *)pUnkRowset;
pIUnknown->AddRef();
pIUnknown->Release();
}
else if (riid == IID_IAccessor)
{
// Use the one we were passed even though it should be the same
SAFE_RELEASE(pIAccessor);
pIAccessor = (IAccessor *)pUnkRowset;
pIAccessor->AddRef();
}
else if (riid == IID_IConvertType)
{
IConvertType * pIConvertType = (IConvertType *)pUnkRowset;
// WSTR is always a mandatory conversion
TESTC_(pIConvertType->CanConvert(DBTYPE_WSTR, DBTYPE_WSTR, DBCONVERTFLAGS_COLUMN), S_OK);
}
else if (riid == IID_IRowset)
{
// Use the one we were passed even though it should be the same
SAFE_RELEASE(pIRowset);
pIRowset = (IRowset *)pUnkRowset;
pIRowset->AddRef();
}
else if (riid == IID_IRowsetInfo)
{
IRowsetInfo * pIRowsetInfo = (IRowsetInfo *)pUnkRowset;
TESTC_(pIRowsetInfo->GetProperties(0, NULL, &cPropertySets, &pPropertySets), S_OK);
TESTC(cPropertySets > 0);
TESTC(pPropertySets != NULL);
TESTC(pPropertySets[0].cProperties > 0);
TESTC(pPropertySets[0].rgProperties != NULL);
TESTC(pPropertySets[0].guidPropertySet == DBPROPSET_ROWSET);
}
else if (riid == IID_IColumnsInfo)
{
IColumnsInfo * pIColumnsInfo = (IColumnsInfo *)pUnkRowset;
DBORDINAL cColumns;
TESTC_(pIColumnsInfo->GetColumnInfo(&cColumns, &pColInfo, &pStringsBuffer), S_OK);
if(fIsRowset)
{
TESTC(cColumns == m_pSelectTable->CountColumnsOnTable()+!pColInfo[0].iOrdinal)
}
else
{
TESTC(cColumns >= m_pSelectTable->CountColumnsOnTable()+!pColInfo[0].iOrdinal)
}
}
else if (riid == IID_IRowsetScroll)
{
DBCOUNTITEM cRowsObtained;
HROW hRow;
HROW * phRow = &hRow;
IRowsetScroll * pIRowsetScroll = (IRowsetScroll *)pUnkRowset;
// Fetch one row at ratio 1/2.
TESTC_(m_hr = pIRowsetScroll->GetRowsAtRatio(NULL, NULL, 1, 2, 1, &cRowsObtained, &phRow), S_OK);
pIRowsetScroll->ReleaseRows(1, phRow, NULL, NULL, NULL);
}
if(!fIsRowset)
{
phAccessor = NULL;
// Row objects don't support binding UDTs as IUnknown
dwBlobType |= BLOB_BIND_UDT_NO_IUNKNOWN;
}
//Create an accessor
m_hr = GetAccessorAndBindings(pIColumnsInfo,
DBACCESSOR_ROWDATA,phAccessor, &rgBindings,
&cBindings, &cbRowSize, DBPART_VALUE | DBPART_LENGTH | DBPART_STATUS,
ALL_COLS_BOUND, FORWARD, NO_COLS_BY_REF,
NULL, NULL, NULL, DBTYPE_EMPTY, 0, NULL,
NULL,NO_COLS_OWNED_BY_PROV, DBPARAMIO_NOTPARAM,
dwBlobType, NULL);
TESTC_(m_hr, S_OK);
//Allocate a new data buffer
pData = (BYTE *)CMultResults::s_pIMalloc->Alloc(cbRowSize);
if (!pData)
{
m_hr = ResultFromScode(E_OUTOFMEMORY);
goto CLEANUP;
}
memset(pData, 0, (size_t)cbRowSize);
if(fIsRowset)
{
//Use IRowset to retrieve data, ask for one more than
//there should be to verify we get DB_S_ENDOFROWSET and
//there aren't too many rows in the rowset
if (DB_S_ENDOFROWSET != (m_hr = pIRowset->GetNextRows(NULL,
0,
m_cRowsInSelect+1,
&cRowsObtained,
(HROW **)&prghRows)))
{
//In this case S_OK is the wrong answer, so bubble up an error to caller
if (m_hr == S_OK)
m_hr = E_FAIL;
goto CLEANUP;
}
//Make sure we got the right number of rows
if (cRowsObtained != m_cRowsInSelect)
{
//Signal user that DB_S_ENDOFROWSET was really returned
//meaning the rowset was empty if no rows are there
if (cRowsObtained == 0)
m_hr = DB_S_ENDOFROWSET;
else
//The rowset isn't empty, so some other failure must have occurred
m_hr = E_FAIL;
goto CLEANUP;
}
}
//From here on out we'll assume success and if this changes
//we'll assign m_hr to the appropriate code and break from the loop
m_hr = NOERROR;
if(!fIsRowset)
cRowsObtained = 1;
for (i=0; i< cRowsObtained; i++)
{
if(fIsRowset)
{
//GetData and fail right away if it doesn't work
m_hr = pIRowset->GetData(prghRows[i], hAccessor, pData);
CHECK(m_hr, S_OK);
}
else
{
pCRow = new CRowObject();
TESTC(pCRow != NULL)
TESTC_(pCRow->SetRowObject(pUnkRowset), S_OK)
TESTC_(pCRow->GetColumns(cBindings, rgBindings, pData), S_OK)
}
fFreeMem = TRUE;
// The first N columns in the rowset are columns from the table, for
// which we must use the proper ordinals in m_rgCompOrds. Columns
// N+1 to cBindings are extra row object columns if this is a row
// object. We cannot use m_rgCompOrds for these columns as they
// have no relation to the "base" columns in the table.
cTableCols = m_pSelectTable->CountColumnsOnTable();
cTableBindings = cBindings;
// Find the last binding within the table
for (iBind = 0; iBind < cBindings; iBind++)
{
if (rgBindings[iBind].iOrdinal > cTableCols)
{
cTableBindings = iBind;
break;
}
}
//Verify data value, length and status are what is expected
if (!COMPARE(CompareData(cTableCols,
m_rgCompOrds,
ROW_SEED+i,
pData,
cTableBindings,
rgBindings,
m_pSelectTable,
CMultResults::s_pIMalloc,
PRIMARY), TRUE))
{
m_hr = E_FAIL;
break;
}
// If there are extra bindings, then compare them without m_rgCompOrds
// This is currently not possible with the existing test design, because
// the test requires two tables. With two tables, one cannot use an ini
// file, and without using an ini file one cannot compare the row object's
// extra columns. So just print a warning until we can restructure the test.
if (cBindings > cTableBindings)
{
odtLog << L"Extra row object columns not compared.\n";
COMPAREW(0, 1);
// Loop through extra bindings and release any interface pointers returned
for (iBind = cTableBindings+1; iBind < cBindings; iBind++)
{
// Release any IUnknown's
if (rgBindings[iBind].wType == DBTYPE_IUNKNOWN)
(*(IUnknown **)(&VALUE_BINDING(rgBindings[iBind], pData)))->Release();
}
/*
//Verify data value, length and status are what is expected
if (!COMPARE(CompareData(0,
NULL,
ROW_SEED+i,
pData,
cBindings - cTableBindings,
rgBindings + cTableBindings,
m_pSelectTable,
CMultResults::s_pIMalloc,
PRIMARY), TRUE))
{
m_hr = E_FAIL;
break;
}
*/
}
if (fFreeMem)
{
ReleaseInputBindingsMemory(cBindings, rgBindings, pData, FALSE);
fFreeMem = FALSE;
}
}
CLEANUP:
if (pIAccessor)
{
if (hAccessor != DB_NULL_HACCESSOR)
{
CHECK(pIAccessor->ReleaseAccessor(hAccessor, NULL), S_OK); // We allow release even when zombied
}
pIAccessor->Release();
}
if (pIRowset)
{
CHECK(pIRowset->ReleaseRows(cRowsObtained,
prghRows,
NULL,
NULL,
NULL), S_OK); // We allow release even when zombied
pIRowset->Release();
pIRowset = NULL;
}
// if (pCRow)
// FreeColAccess(pCRow->m_cColAccess, pCRow->m_rgColAccess, FALSE);
if (fFreeMem)
ReleaseInputBindingsMemory(cBindings, rgBindings, pData, FALSE);
SAFE_FREE(pData);
SAFE_FREE(prghRows);
SAFE_DELETE(pCRow);
SAFE_RELEASE(pIRow);
SAFE_RELEASE(pIUnknown);
SAFE_RELEASE(pIOwnInterface);
SAFE_RELEASE(pIColumnsInfo);
SAFE_RELEASE(pIConvertType);
SAFE_RELEASE(pIRowsetInfo);
if (rgBindings)
CMultResults::s_pIMalloc->Free(rgBindings);
//Clean up fixed buffer
if (pData)
CMultResults::s_pIMalloc->Free(pData);
PROVIDER_FREE(pColInfo);
PROVIDER_FREE(pStringsBuffer);
FreeProperties(&cPropertySets, &pPropertySets);
return m_hr;
}
// CMultResults::~CMultResults --------------------------------------------
//
// DTOR
//
//
CMultResults::~CMultResults()
{
ULONG i;
if (m_pIDBCreateCommand)
{
m_pIDBCreateCommand->Release();
m_pIDBCreateCommand = NULL;
}
if (m_pICommandText)
{
m_pICommandText->Release();
m_pICommandText = NULL;
}
if (m_rgSelectOrds)
{
CMultResults::s_pIMalloc->Free(m_rgSelectOrds);
m_rgSelectOrds = NULL;
}
if (m_rgCompOrds)
{
CMultResults::s_pIMalloc->Free(m_rgCompOrds);
m_rgCompOrds = NULL;
}
if (m_pwszSQLStmt)
{
CMultResults::s_pIMalloc->Free(m_pwszSQLStmt);
m_pwszSQLStmt = NULL;
}
if (m_rgeSQLStmts)
{
CMultResults::s_pIMalloc->Free(m_rgeSQLStmts);
}
if (m_rgResFlags)
{
CMultResults::s_pIMalloc->Free(m_rgResFlags);
}
if (m_rgStmtRowsAffected)
{
CMultResults::s_pIMalloc->Free(m_rgStmtRowsAffected);
}
if (m_pwszNewTableName)
CMultResults::s_pIMalloc->Free(m_pwszNewTableName);
//Free all elements of string table
for (i=0; i<ESTMT_LAST; i++)
{
if(m_rgpwszSQL[i])
CMultResults::s_pIMalloc->Free(m_rgpwszSQL[i]);
if(m_prgProcInfo[i].pwszProcName)
{
// Drop stored proc
CHECK(m_pSelectTable->ExecuteCommand(DROP_PROC, IID_NULL, m_prgProcInfo[i].pwszProcName,
NULL, NULL, NULL, EXECUTE_IFNOERROR, 0, NULL, NULL, NULL, NULL), S_OK);
SAFE_FREE(m_prgProcInfo[i].pwszProcName);
SAFE_FREE(m_prgProcInfo[i].prgParamColMap);
}
}
}
// CMultResults::CheckErrorOutParams ------------------------------------------------
//
// Verifies that the GetResults out parameters are correctly set when method
// returns an error. Assumes GetResult is always called with pcRowsAffected
// as &this->m_cRowsGetResultAffected.
//
//
BOOL CMultResults::CheckErrorOutParams(IUnknown * pRowset)
{
if (COMPARE(pRowset, NULL))
if (COMPARE(m_cRowsGetResultAffected, DB_COUNTUNAVAILABLE))
return TRUE;
return FALSE;
}
//////////////////////////////////////////////////////////////////
// CBatch
//////////////////////////////////////////////////////////////////
// CBatch::SetAndExecute ------------------------------------------------
//
// Implementation of pure virtual function from CMultResults. Sets SQL in proper
// format for a batch statement and executes it. The execute is done by calling
// CMultResults::Execute().
//
//
HRESULT CBatch::SetAndExecute(REFIID riid)
{
//For pure batched statements, just build a string of
//all SQL stmts concatenated together, separated by spaces
if (SUCCEEDED(m_hr = BuildConcatSQL()))
//Set that string
if (SUCCEEDED(m_hr = m_pICommandText->SetCommandText(DBGUID_DBSQL, m_pwszSQLStmt)))
//Execute it
m_hr = Execute(riid, NULL);
return m_hr;
}
// CBatch::FInit ------------------------------------------------
//
// Does post construction initialization.
//
//
BOOL CBatch::FInit(const ULONG cSQLStmts, ESQLSTMT * rgSQLStmts, DBRESULTFLAG* rgResFlags)
{
DBCOUNTITEM * rgRowsAffected = NULL;
ULONG i;
DBCOUNTITEM cTotalRowsAffected = 0;
BOOL fResults = FALSE;
ULONG cInserts = 0;
////////////////////////////////////////////////////
//All we need to do is determine the parameters that
//are derived class specific, then delegate to our
//base class FInit
////////////////////////////////////////////////////
//Alloc memory for our array
rgRowsAffected = (DBCOUNTITEM *)CMultResults::s_pIMalloc->Alloc((size_t)(cSQLStmts * sizeof(DBCOUNTITEM)));
if (!rgRowsAffected)
goto CLEANUP;
//Find out how many rows we have, should always be more than 0
//Note we count this each time so that if previous variations' inserts
//fail we still have an accurate count of how many rows are
//actually in the table.
m_cRowsInChgTable = m_pChangeTable->CountRowsOnTable();
TESTC(m_cRowsInChgTable > 0);
//Free the CTable command that was created in CountRowsOnTable
//so that we can be in firehose mode when we execute
if (m_pChangeTable->get_ICommandPTR())
{
m_pChangeTable->get_ICommandPTR()->Release();
m_pChangeTable->set_ICommandPTR(NULL);
}
//Figure out how many rows each statement in the batch
//affects, and init corresponding array element to that value
for (i=0; i<cSQLStmts; i++)
{
switch(rgSQLStmts[i])
{
case ESELECT:
case EEMPTYSELECT:
case ECREATE:
case EDROP:
case ECOMPUTESUM:
case ESELECTWAIT:
//This is undefined, to flag it's not to be looked at
rgRowsAffected[i] = -1;
break;
case EDELETE:
//Our delete clause should never find any rows
rgRowsAffected[i] = 0;
break;
case EUPDATE:
//The update will always affect all rows in the table
//which is number of rows existing when we start
//the batch plus number of inserts we've done so far
//in this batch
rgRowsAffected[i] = m_cRowsInChgTable + cInserts;
break;
case EINSERT:
//We always insert just one row
rgRowsAffected[i] = 1;
//Keep track of how many inserts we do in this batch
//so we know how many rows updates will affect
cInserts++;
break;
default:
//Need to add code to deal with any other enum values
ASSERT(FALSE);
}
}
//Just add up all of the above (which are row affecting) to find
//the total for a batch statement's total rows affected
for (i=0; i<cSQLStmts; i++)
if (rgSQLStmts[i] == EUPDATE ||
rgSQLStmts[i] == EINSERT ||
rgSQLStmts[i] == EDELETE)
//Add the total for this element
cTotalRowsAffected += rgRowsAffected[i];
//Now delegate to our base class FInit, it copies rgRowsAffected
fResults =CMultResults::FInit(cSQLStmts, rgSQLStmts, rgResFlags, rgRowsAffected);
// The non-parameterized select returns all rows in the table.
m_cRowsInSelect = m_pSelectTable->CountRowsOnTable();
TESTC(m_cRowsInSelect > 0);
CLEANUP:
//Free our array since FInit only copied it and doesn't own it
if (rgRowsAffected)
CMultResults::s_pIMalloc->Free(rgRowsAffected);
return fResults;
}
//////////////////////////////////////////////////////////////////
// CParamSets
//////////////////////////////////////////////////////////////////
// CParamSets::CParamSets --------------------------------------------
//
// CTOR
//
//
CParamSets::CParamSets(ULONG cParamSets,
IDBCreateCommand * pIDBCreateCommand,
ICommandText * pICommandText,
CTable * pSelectTable,
CTable * pChangeTable)
: CMultResults(pIDBCreateCommand,
pICommandText,
pSelectTable,
pChangeTable)
{
m_cTotalRowsAffected = 0;
m_dbParams.pData = NULL;
m_dbParams.cParamSets = cParamSets;
m_dbParams.hAccessor = DB_NULL_HACCESSOR;
m_rgBindings = NULL;
m_cBindings = 0;
m_pIAccessor = NULL;
m_prgStmtInfo = NULL;
m_prgResultMap = NULL;
}
// CParamSets::~CParamSets --------------------------------------------
//
// DTOR
//
//
CParamSets::~CParamSets()
{
if (m_rgBindings)
{
CMultResults::s_pIMalloc->Free(m_rgBindings);
m_rgBindings = NULL;
}
if (m_dbParams.pData)
{
CMultResults::s_pIMalloc->Free(m_dbParams.pData);
m_dbParams.pData = NULL;
}
if (m_pIAccessor)
{
if (m_dbParams.hAccessor)
{
m_pIAccessor->ReleaseAccessor(m_dbParams.hAccessor, NULL);
m_dbParams.hAccessor = DB_NULL_HACCESSOR;
}
m_pIAccessor->Release();
m_pIAccessor = NULL;
}
SAFE_FREE(m_prgStmtInfo);
SAFE_FREE(m_prgResultMap);
}
// CParamSets::SetAndExecute ------------------------------------------------
//
// Implementation of pure virtual function from CMultResults. Sets SQL in proper
// format for a batch statement and executes it. The execute is done by calling
// CMultResults::Execute().
//
//
HRESULT CParamSets::SetAndExecute(REFIID riid)
{
//Build SQL statement -- for this class there is only one
//statement to concat, but we can still use this function.
if (SUCCEEDED(m_hr = BuildConcatSQL()))
//Set that string
if (SUCCEEDED(m_hr = m_pICommandText->SetCommandText(DBGUID_DBSQL, m_pwszSQLStmt)))
{
//Execute it with Param structs
m_hr = Execute(riid, &m_dbParams);
}
return m_hr;
}
// CParamSets::CalcTotalResultsExpected ------------------------------------------------
//
// Calculates the proper m_cTotalResultsExpected
//
//
BOOL CParamSets::CalcTotalResultsExpected()
{
ULONG iStmt = 0, iSet = 0;
BOOL fResult = FALSE;
//////////////////////////////////////////////////////
//Find how many results we expect and modify the
//appropriate data members
//////////////////////////////////////////////////////
SAFE_FREE(m_prgResultMap);
// Assume we will have one result for each statement and param set
SAFE_ALLOC(m_prgResultMap, ULONG, m_ceSQLStmts * m_dbParams.cParamSets);
memset(m_prgResultMap, 0, m_ceSQLStmts * m_dbParams.cParamSets * sizeof(ULONG));
//Override the default results count calculated in CMultResults::FInit
m_cTotalResultsExpected = 0;
for (iSet = 0; iSet < m_dbParams.cParamSets; iSet++)
{
for (iStmt=0; iStmt< m_ceSQLStmts; iStmt++)
{
if (IsResultProducing(iStmt))
{
// Rowsets are always returned before RPC out params in a result batch
if (iStmt && m_cTotalResultsExpected &&
m_rgeSQLStmts[m_prgResultMap[m_cTotalResultsExpected-1]] == ERPCSELECTOUT && // Previous stmt is filling out params only
(m_rgeSQLStmts[iStmt] == ESELECT || m_rgeSQLStmts[iStmt]== ESELECTWAIT)) // Current stmt is returning a rowset
{
// The current result will be returned before the previous one, swap them
ULONG ulPrevStmt = m_prgResultMap[m_cTotalResultsExpected-1];
m_prgResultMap[m_cTotalResultsExpected-1] = iStmt;
m_prgResultMap[m_cTotalResultsExpected] = ulPrevStmt;
m_prgStmtInfo[ulPrevStmt].fCombinedResult = TRUE;
}
else
{
m_prgResultMap[m_cTotalResultsExpected]=iStmt;
m_prgStmtInfo[iStmt].fCombinedResult = FALSE;
}
m_cTotalResultsExpected++;
}
}
}
// A single insert statement with params and multiple paramsets returns only one result
// A single sproc filling output params returns only one result
if ((m_rgeSQLStmts[0] == EINSERT || m_rgeSQLStmts[0] == ERPCSELECTOUT) && m_ceSQLStmts == 1)
{
m_cTotalResultsExpected = 1;
m_prgResultMap[0] = 0;
}
// We should always have at least one result. This is the case when we have all RPC out params without streams.
if (!m_cTotalResultsExpected)
m_cTotalResultsExpected++;
fResult = TRUE;
CLEANUP:
return fResult;
}
// CParamSets::CalcTotalRowsAffected ------------------------------------------------
//
// Calculates the proper m_cTotalRowsAffected
//
//
void CParamSets::CalcTotalRowsAffected()
{
ULONG i = 0;
//////////////////////////////////////////////////////
//Find the total rows affected by the whole execution
//////////////////////////////////////////////////////
m_cTotalRowsAffected = 0;
for (i=0; i< m_ceSQLStmts; i++)
{
switch (m_rgeSQLStmts[i])
{
case ESELECT:
case ERPCSELECTOUT:
; //No rows affected for a select.
break;
case EINSERT:
//We always insert just one row for a single param set
m_cTotalRowsAffected += m_dbParams.cParamSets;
break;
default:
//Need to add code to deal with any other enum values
ASSERT(FALSE);
}
}
}
// CParamSets::FInit ------------------------------------------------
//
// Does post construction initialization.
//
//
BOOL CParamSets::FInit(const ULONG cSQLStmts, ESQLSTMT * rgSQLStmts, DBRESULTFLAG* rgResFlags,
ULONG cResFlags, ULONG ulRowNum)
{
DBCOUNTITEM * rgRowsAffected = NULL;
ULONG i = 0;
ULONG j = 0;
ULONG cTotalRowsAffected = 0;
BOOL fResults = FALSE;
ULONG cInserts = 0;
LPWSTR pwszCreateRPC = NULL;
DBORDINAL cParams;
DB_LORDINAL * prgParamColMap = NULL;
LPWSTR pwszProcName = NULL;
LPWSTR pwszExecRPC = NULL;
////////////////////////////////////////////////////
//Perform CParamSets specific initialization,
//determine the parameters that are derived class specific,
//then delegate to our base class FInit
////////////////////////////////////////////////////
//Alloc memory for our count of rows affected array
rgRowsAffected = (DBCOUNTITEM *)CMultResults::s_pIMalloc->Alloc((size_t)(cSQLStmts * sizeof(DBCOUNTITEM)));
if (!rgRowsAffected)
goto CLEANUP;
// Allocate and init memory for StmtInfo array
SAFE_ALLOC(m_prgStmtInfo, StmtInfo, cSQLStmts);
memset(m_prgStmtInfo, 0, sizeof(StmtInfo)*cSQLStmts);
m_ceSQLStmts = cSQLStmts;
m_rgeSQLStmts = rgSQLStmts;
if(rgResFlags)
{
m_rgResFlags =
(DBRESULTFLAG *)CMultResults::s_pIMalloc->Alloc(cResFlags * sizeof(DBRESULTFLAG));
if (!m_rgResFlags)
goto CLEANUP;
memcpy(m_rgResFlags, rgResFlags, cResFlags * sizeof(DBRESULTFLAG));
}
//Set m_cTotalRowsAffected
CalcTotalRowsAffected();
//Fill the rows affected array
for (i=0; i<cSQLStmts; i++)
{
//For param sets, each individual count is the total rows affected
rgRowsAffected[i] = m_cTotalRowsAffected;
}
//Now delegate to our base class FInit, it copies rgRowsAffected
if (CMultResults::FInit(cSQLStmts, rgSQLStmts, NULL, rgRowsAffected))
{
//Now override the SQL statments we built in CMultResults::FInit
//to use parametmers, also build accessors and data needed
//for param execution
//Free non parameterized statement
if (m_rgpwszSQL[ESELECT])
{
//Free first since we've built this table
//once in our base FInit and want to redo
//this string in it
CMultResults::s_pIMalloc->Free(m_rgpwszSQL[ESELECT]);
m_rgpwszSQL[ESELECT] = NULL;
}
if (FAILED(m_pSelectTable->CreateSQLStmt(
SELECT_ALL_WITH_SEARCHABLE_AND_UPDATEABLE,
NULL,
&m_rgpwszSQL[ESELECT],
NULL,
NULL, ulRowNum)))
goto CLEANUP;
//Free non parameterized statement
if (m_rgpwszSQL[EINSERT])
{
//Free first since we've built this table
//once in our base FInit and want to redo
//this string in it
CMultResults::s_pIMalloc->Free(m_rgpwszSQL[EINSERT]);
m_rgpwszSQL[EINSERT] = NULL;
}
if (FAILED(m_pChangeTable->InsertWithParams(
ROW_SEED,
PRIMARY,
FALSE, // Don't execute
&m_rgpwszSQL[EINSERT])))
goto CLEANUP;
//Free non parameterized statement
if (m_rgpwszSQL[ERPCSELECTOUT])
{
//Free first since we've built this table
//once in our base FInit and want to redo
//this string in it
CMultResults::s_pIMalloc->Free(m_rgpwszSQL[ERPCSELECTOUT]);
m_rgpwszSQL[ERPCSELECTOUT] = NULL;
}
// Create a stored proc name and save it so we can drop the sproc later
pwszProcName = MakeObjectName(L"IMultSelSproc", 30);
TESTC_(m_pSelectTable->CreateSQLStmt(
RPC_SELECT_ALL_BYINDEX_WITHPARAMS,
pwszProcName,
&pwszCreateRPC,
&cParams,
&prgParamColMap), S_OK);
m_prgProcInfo[ERPCSELECTOUT].pwszProcName = pwszProcName; // Dropped and freed in destructor
m_prgProcInfo[ERPCSELECTOUT].cParams = cParams;
m_prgProcInfo[ERPCSELECTOUT].prgParamColMap = prgParamColMap;
m_prgProcInfo[ERPCSELECTOUT].cParamIO = cParams - 1; // Last param is the input-only param.
m_prgProcInfo[ERPCSELECTOUT].eParamIO = DBPARAMIO_OUTPUT; // First block of params are all output params
TESTC_(m_pSelectTable->BuildCommand(pwszCreateRPC, IID_NULL,
EXECUTE_IFNOERROR, 0, NULL, NULL, NULL, NULL, NULL), S_OK);
TESTC_(m_pSelectTable->CreateSQLStmt(
CALL_RPC,
pwszProcName, // If we created a stored proc this will create the "call" stmt
&pwszExecRPC, // Freed in destructor
&cParams,
NULL), S_OK);
m_rgpwszSQL[ERPCSELECTOUT] = pwszExecRPC;
//Override the total num of results expected
//which was set in CMultResults::FInit, since
//param sets cause a different number of
//results than just the number of statements
//in the batch
TESTC(CalcTotalResultsExpected());
if (FAILED(BuildParamAccessorAndData(cSQLStmts)))
goto CLEANUP;
// We only expect one row from the parameterized
// select stmt.
m_cRowsInSelect = 1;
//We're OK if we made it this far
fResults = TRUE;
}
CLEANUP:
//Free our array since FInit only copied it and doesn't own it
if (rgRowsAffected)
CMultResults::s_pIMalloc->Free(rgRowsAffected);
SAFE_FREE(pwszCreateRPC);
return fResults;
}
// CParamSets::ProcessAllResults --------------------------------------------
//
// Verifies everything about all results remaining for this result object
// (ie, the executed ole db command object), then releases all interfaces
// received from Execute and GetResult.
//
// NOTE: riidGetResult is the iid asked for on GetResult calls, and does not
// apply to Execute.
// If cTotalResults is -1, the number of statements in the batch is used as
// the total expected number of results.
//
HRESULT CParamSets::ProcessAllResults(ULONG cResultsAlreadyProcessed,
REFIID riidExecute,
IID* rgRiidGetResult)
{
ULONG i;
IUnknown * pUnkRowset = NULL;
ULONG ulCurSQLStmt = cResultsAlreadyProcessed;
ULONG ulCurParamSet = 1;
HRESULT hrGetResult = S_OK;
//This will be our return value variable
m_hr = S_OK;
if (m_pIMultResults)
{
//Starting at index cResultsAlreadyProcessed will put
//us at the next element to be processed since the
//array is 0-based and cResultsAlreadyProcessed is 1-based
for (i=cResultsAlreadyProcessed; i<m_cTotalResultsExpected; i++)
{
// "Combined" results do not require a GetResult call, typically this is filling output params prior to
// returning a rowset in the batch.
if (!m_prgStmtInfo[m_prgResultMap[i]].fCombinedResult)
{
hrGetResult = ComputeGetResultHR(i);
m_hr = m_pIMultResults->GetResult(NULL,
m_rgResFlags[i],
rgRiidGetResult[i],
&m_cRowsGetResultAffected,
(IUnknown **)&pUnkRowset);
odtLog << L"***GetResult for result " << i << L" returned " << m_hr << L"\n";
}
if (CHECK(m_hr, hrGetResult))
{
//Check everything is correct for this result
if (!AreGetResultOutParamsRight(ulCurSQLStmt, pUnkRowset, rgRiidGetResult[i], m_rgResFlags[i]))
{
m_hr = E_FAIL;
odtLog << L"GetResult output params are not right for result: " << i+1 << wszNewLine;
goto CLEANUP;
}
}
else
{
m_hr = E_FAIL;
odtLog << L"GetResult did not return " << hrGetResult << L" for result: " << i+1 << wszNewLine;
goto CLEANUP;
}
//Release this rowset if it exists
if (pUnkRowset)
{
pUnkRowset->Release();
pUnkRowset = NULL;
odtLog << L"Rowset released for result " << i << L"\n";
CHECK(m_hr, S_OK);
}
}
//Init to garbage so we can tell that it is cleared by this method
pUnkRowset = (IUnknown *)0x12345678;
//We should have retrieved all results already, so next should be DB_S_NORESULT
hrGetResult = DB_S_NORESULT;
if (hrGetResult == (m_hr = m_pIMultResults->GetResult(NULL,
0,
rgRiidGetResult[i-1],
&m_cRowsGetResultAffected,
(IUnknown **)&pUnkRowset)))
{
//Pass an iResult of i, which means we've gone passed all
//possible results. This function will then look for
//*ppRowset = NULL and *pcRowsAffected = -1.
if (!AreGetResultOutParamsRight(i, pUnkRowset, rgRiidGetResult[i-1], 0))
{
m_hr = E_FAIL;
goto CLEANUP;
}
}
else
{
goto CLEANUP;
}
//Now release interface received from Execute
ReleaseIMultipleResults();
}
else
{
//Verify Execute's result matches the first result expected
if (!AreExecuteOutParamsRight(riidExecute, m_pIRowset))
{
m_hr = E_FAIL;
odtLog << L"Execute output params are not right for first result." << wszNewLine;
}
//Now release interface received from Execute
ReleaseIRowset();
}
CLEANUP:
ReleaseIMultipleResults();
if (pUnkRowset)
{
pUnkRowset->Release();
pUnkRowset = NULL;
}
return (hrGetResult == m_hr) ? S_OK : m_hr;
}
// CParamSets::BuildParamAccessorAndData ------------------------------------
//
// Builds all needed parameter stuff for execution
//
//
HRESULT CParamSets::BuildParamAccessorAndData(const ULONG cSQLStmts)
{
EQUERY eQuery;
WCHAR * wszTempQuery = NULL;
ULONG cParamCols = 0;
CCol tempCol;
BYTE * pSetOffset = NULL;
ULONG i = 0;
ULONG j = 0;
ULONG k = 0;
DBBINDING * pCurBindings = NULL;
DB_LORDINAL * pCurParamCols = NULL;
DBCOUNTITEM cCurBindings = 0;
DBLENGTH cbCurRowSize = 0;
DBBINDSTATUS * prgBindStatus = NULL;
BLOBTYPE dwBlobType = BLOB_LONG;
DWORD dwColsToBind = ALL_COLS_BOUND;
m_cbRowSize = 0;
m_cBindings = 0;
m_hr = E_FAIL;
//Get rid of the select col list that non parameterized
//statements use
if (m_rgSelectOrds)
{
CMultResults::s_pIMalloc->Free(m_rgSelectOrds);
m_rgSelectOrds = NULL;
}
if (m_rgCompOrds)
{
CMultResults::s_pIMalloc->Free(m_rgCompOrds);
m_rgCompOrds = NULL;
}
//Get Accessor interface
if (!m_pIAccessor)
{
if (FAILED(m_hr = m_pICommandText->QueryInterface(IID_IAccessor,
(void **)&m_pIAccessor)))
goto CLEANUP;
}
if (m_dbParams.hAccessor)
{
TESTC_(m_pIAccessor->ReleaseAccessor(m_dbParams.hAccessor, NULL), S_OK);
}
if (m_dbParams.pData)
{
ReleaseInputBindingsMemory(m_cBindings, m_rgBindings, (BYTE *)m_dbParams.pData, TRUE);
}
//Alloc arrays which are sure to be large enough,
//but we may not use all of the size we alloc
//Use 2*column count because we may create parameters for more than the columns in the table.
//Worst case is all columns as input params and all columns as output params.
m_rgSelectOrds =
(DB_LORDINAL *)CMultResults::s_pIMalloc->Alloc(2*m_pSelectTable->CountColumnsOnTable()
* cSQLStmts * sizeof(DB_LORDINAL) * m_dbParams.cParamSets);
m_rgCompOrds =
(DB_LORDINAL *)CMultResults::s_pIMalloc->Alloc(2*m_pSelectTable->CountColumnsOnTable()
* cSQLStmts * sizeof(DB_LORDINAL) * m_dbParams.cParamSets);
if (m_rgBindings)
{
CMultResults::s_pIMalloc->Free(m_rgBindings);
m_rgBindings = NULL;
}
m_rgBindings =
(DBBINDING *)CMultResults::s_pIMalloc->Alloc(2*m_pSelectTable->CountColumnsOnTable()
* cSQLStmts * sizeof(DBBINDING) * m_dbParams.cParamSets);
prgBindStatus =
(DBBINDSTATUS *)CMultResults::s_pIMalloc->Alloc(m_pSelectTable->CountColumnsOnTable()
* cSQLStmts * sizeof(DBBINDSTATUS) * m_dbParams.cParamSets);
if (!m_rgBindings || !m_rgSelectOrds || !m_rgCompOrds)
{
m_hr = E_OUTOFMEMORY;
goto CLEANUP;
}
////////////////////////////////////////////////////
//Setup according to what kind of parameters we have
////////////////////////////////////////////////////
//For each statement in the batch
for (k=0; k<m_ceSQLStmts; k++)
{
// Assume we do not have a stream binding and any out params are not yet processed for this statement
// m_prgStmtInfo[k].fHasStreamBinding = FALSE; // Assume we are not binding out params as stream
m_prgStmtInfo[k].fOutParamsProcessed = FALSE; // Have not yet processed (verified) these out params
//Set our offset to the right place in m_rgSelectOrds
//for this portion of the batch
pCurParamCols = &m_rgSelectOrds[m_cBindings];
switch (m_rgeSQLStmts[k])
{
case EINSERT:
{
//Our temp query will be all updateable cols
eQuery = SELECT_UPDATEABLE;
//Build array of all updateable cols' ordinals
for (i=1, j=0; i<=m_pSelectTable->CountColumnsOnTable(); i++)
{
m_pSelectTable->GetColInfo(i, tempCol);
if (tempCol.GetUpdateable())
{
pCurParamCols[j] = i;
j++;
}
}
break;
}
case ESELECT:
{
//Our temp query will be one which finds all
//columns which work in a parameterized where clause
eQuery = SELECT_ALL_WITH_SEARCHABLE_AND_UPDATEABLE;
//Build array of all cols which will be in the
//SELECT_ALL_WITH_SEARCHABLE_AND_UPDATEABLE statement.
//We don't use any long columns as they are illegal in a LIKE clause if
//over 255 chars on SQL Server.
for (i=1, j=0; i<=m_pSelectTable->CountColumnsOnTable(); i++)
{
m_pSelectTable->GetColInfo(i, tempCol);
if (tempCol.GetSearchable() != DB_UNSEARCHABLE &&
!tempCol.GetIsLong() &&
tempCol.GetUpdateable())
{
pCurParamCols[j] = i;
m_rgCompOrds[j] = i;
j++;
}
}
break;
}
case ERPCSELECTOUT:
{
eQuery = SELECT_ALLFROMTBL;
for (j=0; j < m_prgProcInfo[m_rgeSQLStmts[k]].cParams; j++)
pCurParamCols[j] = m_prgProcInfo[m_rgeSQLStmts[k]].prgParamColMap[j];
break;
}
default:
{
//We need to add more code for addional enum values
ASSERT(FALSE);
}
}
//Remember total number of param ordinals we found
cParamCols += j;
////////////////////////////////////////////////
//Create Accessor
////////////////////////////////////////////////
//Temporarily set query to contain all correct
//columns so we can figure out
//the binding info on the parameters for our
//parameterized statement
if (FAILED(m_hr = m_pSelectTable->CreateSQLStmt(
eQuery,
NULL,
&wszTempQuery,
NULL,
NULL)))
goto CLEANUP;
if (FAILED(m_hr = m_pICommandText->SetCommandText(DBGUID_DBSQL,
wszTempQuery)))
goto CLEANUP;
if (wszTempQuery)
CMultResults::s_pIMalloc->Free(wszTempQuery);
wszTempQuery = NULL;
// For stored procs we need to generate and use our own ordinals of underlying columns to bind.
if (m_prgProcInfo[m_rgeSQLStmts[k]].pwszProcName)
dwColsToBind = USE_COLS_TO_BIND_ARRAY;
else
dwColsToBind = ALL_COLS_BOUND;
// Bind all BLOBs as stream if requested.
if (m_prgStmtInfo[k].fHasStreamBinding)
dwBlobType = BLOB_IID_ISEQSTREAM | BLOB_BIND_ALL_BLOBS;
else
dwBlobType = BLOB_LONG;
//Use the temp query to generate bindings for this portion of the batch
if (FAILED(m_hr = GetAccessorAndBindings(m_pICommandText,
DBACCESSOR_PARAMETERDATA,
&m_dbParams.hAccessor,
&pCurBindings,
&cCurBindings,
&cbCurRowSize,
DBPART_VALUE | DBPART_LENGTH | DBPART_STATUS,
dwColsToBind, //Use param array we built ourselves (use USE_COLS_TO_BIND_ARRAY for RPCs)
FORWARD,
NO_COLS_BY_REF,
NULL,
NULL,
NULL,
DBTYPE_EMPTY,
m_prgProcInfo[m_rgeSQLStmts[k]].cParams, // cColsToBind, 0 for non-RPC
m_prgProcInfo[m_rgeSQLStmts[k]].prgParamColMap, // rgColsToBind, NULL for non-RPC
s_rgParamOrdinals,
NO_COLS_OWNED_BY_PROV,
DBPARAMIO_INPUT,
dwBlobType))) //Bind all cols since we include then in SQL stmt
goto CLEANUP;
// Keep track of the parameter count for each statement
m_prgStmtInfo[k].cParams = cCurBindings;
//Adjust the offsets and paramio if needed
for (ULONG i=0; i<cCurBindings; i++)
{
pCurBindings[i].obValue += m_cbRowSize;
pCurBindings[i].obLength += m_cbRowSize;
pCurBindings[i].obStatus += m_cbRowSize;
// We assume that any non-input params will be all together in a common block in the first bindings,
// which is true for all statements and sprocs currently generated. Currently only used for stored procs
if (i < m_prgProcInfo[m_rgeSQLStmts[k]].cParamIO)
pCurBindings[i].eParamIO = m_prgProcInfo[m_rgeSQLStmts[k]].eParamIO;
}
//Adjust our total binding values to include the partial ones we just built
memcpy(&m_rgBindings[m_cBindings], pCurBindings, (size_t)(cCurBindings * sizeof(DBBINDING)));
m_cBindings +=cCurBindings;
m_cbRowSize +=cbCurRowSize;
//Free what was allocated in GetAccessorAndBindings since we've
//already copied it into m_rgBindings
CMultResults::s_pIMalloc->Free(pCurBindings);
//Release this accessor since we only want the bindings
m_pIAccessor->ReleaseAccessor(m_dbParams.hAccessor, NULL);
m_dbParams.hAccessor = DB_NULL_HACCESSOR;
}
/////////////////////////////////////////////////////////
//Now create the real accessor with the total binding info
/////////////////////////////////////////////////////////
//Set the correct ordinals
for (i=0; i<m_cBindings; i++)
m_rgBindings[i].iOrdinal = s_rgParamOrdinals[i];
if ((m_hr = m_pIAccessor->CreateAccessor(DBACCESSOR_PARAMETERDATA,
m_cBindings,
m_rgBindings,
m_cbRowSize,
&m_dbParams.hAccessor,
prgBindStatus)) != S_OK)
goto CLEANUP;
////////////////////////////////////////////////
//Build the data
////////////////////////////////////////////////
//Allocate a buffer big enough for all the param sets
m_dbParams.pData =
(BYTE *)CMultResults::s_pIMalloc->Alloc(m_dbParams.cParamSets * m_cbRowSize);
if (!m_dbParams.pData)
{
m_hr = E_OUTOFMEMORY;
goto CLEANUP;
}
for (i=0; i<m_dbParams.cParamSets; i++)
{
pSetOffset = (BYTE *)m_dbParams.pData + (i*m_cbRowSize);
if (FAILED(m_hr = FillInputBindings(m_pChangeTable,
DBACCESSOR_PARAMETERDATA,
m_cBindings,
m_rgBindings,
&pSetOffset,
ROW_SEED,
cParamCols,
m_rgSelectOrds,
PRIMARY)))
goto CLEANUP;
// Re-fill output-only params with invalid data. Note that we should expect FillInputBindings to do that for us
// but to prevent side effects for the case where we actually use this to generate correct data for comparison
// I have not changed FillInputBindings.
for (ULONG i=0; i < m_cBindings; i++)
{
if (m_rgBindings[i].eParamIO == DBPARAMIO_OUTPUT)
memset(pSetOffset+m_rgBindings[i].obValue, FILL_PATTERN, m_rgBindings[i].cbMaxLen);
}
}
CLEANUP:
if (wszTempQuery)
CMultResults::s_pIMalloc->Free(wszTempQuery);
if (prgBindStatus)
CMultResults::s_pIMalloc->Free(prgBindStatus);
return m_hr;
}
BOOL CParamSets::AreGetResultOutParamsRight(ULONG iResult, IUnknown * pUnkRowset, REFIID riid, DBRESULTFLAG resFlag)
{
BOOL fResult = FALSE;
//If we have called GetResult for more times that we have results,
//*ppRowset must be NULL and *pcRowsAffected must be -1 and no
//further checking is necessary. This is the DB_S_NORESULT case.
if (iResult >= m_cTotalResultsExpected)
{
if (pUnkRowset == NULL &&
m_cRowsGetResultAffected == -1)
return TRUE;
else
return FALSE;
}
// Rowsets are always returned before out params
// And if a rowset was preferentially returned first then any subsequent out params will be filled
// with the rowset
switch (m_rgeSQLStmts[m_prgResultMap[iResult]])
{
case EINSERT:
odtLog << L"Expecting EINSERT result.\n";
break;
case EDELETE:
odtLog << L"Expecting EDELETE result.\n";
break;
case EUPDATE:
odtLog << L"Expecting EUPDATE result.\n";
break;
case ECREATE:
odtLog << L"Expecting ECREATE result.\n";
break;
case EDROP:
odtLog << L"Expecting EDROP result.\n";
break;
case ESELECT:
odtLog << L"Expecting ESELECT result.\n";
break;
case ESELECTWAIT:
odtLog << L"Expecting ESELECTWAIT result.\n";
break;
case EEMPTYSELECT:
odtLog << L"Expecting EEMPTYSELECT result.\n";
break;
case ERPCSELECTOUT:
odtLog << L"Expecting ERPCSELECTOUT result.\n";
break;
default:
odtLog << L"Found unknown result.\n";
break;
}
switch (m_rgeSQLStmts[m_prgResultMap[iResult]])
{
case EINSERT:
case EDELETE:
case EUPDATE:
//we can check the row count
if (IsGetResultRowsAffectedRight(m_prgResultMap[iResult]))
//and the rowset interface returned must be NULL
fResult = (NULL == pUnkRowset);
break;
case ECREATE:
case EDROP:
//Row count is undefined, only check rowset is null
fResult = (NULL == pUnkRowset);
break;
case ESELECT:
case ESELECTWAIT:
if (pUnkRowset)
fResult = (S_OK == VerifySelectRowset(riid, pUnkRowset, IsRowset(riid, resFlag)));
break;
case EEMPTYSELECT:
if (pUnkRowset)
fResult = (DB_S_ENDOFROWSET == VerifySelectRowset(riid, pUnkRowset, IsRowset(riid, resFlag)));
break;
case ERPCSELECTOUT:
fResult = VerifyOutParams(iResult);
// If this result was not combined with a previous rowset then make sure rowset pointer is NULL
if (!m_prgStmtInfo[m_prgResultMap[iResult]].fCombinedResult)
fResult = fResult && (NULL == pUnkRowset);
break;
default:
//Need to add more code for other enums
fResult = FALSE;
ASSERT(FALSE);
}
//We haven't returned through one of our successful paths,
//meaning there was an error, so return FALSE
return fResult;
}
BOOL CParamSets::VerifyOutParams(ULONG iResult)
{
ULONG iStmt, iStmtStart, iStmtEnd;
DBORDINAL iBindStart=0, iBind;
DB_UPARAMS iSet, iSetStart, iSetEnd;
DBORDINAL cParams = 0;
BYTE * pOffSet = NULL;
BOOL fResult = FALSE;
BOOL fCmpErr = FALSE;
TESTC(iResult < m_cTotalResultsExpected);
cParams = m_prgProcInfo[m_rgeSQLStmts[m_prgResultMap[iResult]]].cParams;
// Validate only this one result/statement/parameter set
iSet = iResult / CalcResultGroups();
iSetStart = iSet;
iSetEnd = iSet+1; // Only use one param set
// For a single RPC filling out params, even with streams all parameter sets are populated at once
if (m_ceSQLStmts == 1 && m_rgeSQLStmts[0] == ERPCSELECTOUT)
iSetEnd = m_dbParams.cParamSets;
iStmtStart = m_prgResultMap[iResult];
iStmtEnd = iStmtStart+1; // Only use one stmt
for (iStmt = 0; iStmt < iStmtStart; iStmt++)
iBindStart += m_prgStmtInfo[m_rgeSQLStmts[iStmt]].cParams;
for (; iSet <iSetEnd; iSet++)
{
pOffSet = (BYTE *)m_dbParams.pData + (iSet*m_cbRowSize);
for (iBind = iBindStart; iBind < iBindStart+cParams; iBind++)
{
if (m_rgBindings[iBind].eParamIO & DBPARAMIO_OUTPUT)
{
if (m_rgBindings[iBind].pObject)
{
DBSTATUS * pStatus = (DBSTATUS *)(((BYTE *)pOffSet)+m_rgBindings[iBind].obStatus);
if (*pStatus == DBSTATUS_S_OK)
odtLog << L"Found stream to be processed.\n";
}
if (!COMPARE(CompareData(
iBindStart+cParams, //@parm [in]: the count of rgColumnsOrd
m_rgSelectOrds, //@parm [in]: the array of column ordinals in the backend table.
// The column ordinals in the backend table is
// not the same as ordinals in the rowset.
ROW_SEED, //@parm[in]: the row number of the data at the backend table
pOffSet, //@parm[in]: the pointer to the buffer which contains the data
// to be compared with
1, //@parm[in]: the count of the rgBindings
&m_rgBindings[iBind], //@parm[in]: the binding information of the accessor which
// retrieved the data
m_pSelectTable, //@parm[in]: The pointer to CTable object from which the
// the rowset was created.
CMultResults::s_pIMalloc, //@parm[in]: the IMalloc pointer used to free memory.
// can not be NULL.
PRIMARY), TRUE)) //@parm[in]: whether use PRIMARY or SECONDARY to make a data
fCmpErr = TRUE;
}
}
}
fResult = fCmpErr ? FALSE : TRUE;
CLEANUP:
return fResult;
}
BOOL CParamSets::SetOutParamBindType(ULONG iStmt, BOOL fHasStreamBinding)
{
if (iStmt < m_ceSQLStmts)
{
m_prgStmtInfo[iStmt].fHasStreamBinding = fHasStreamBinding;
// Since we changed the stream bindings we will now have more or less results to consume, recompute them.
return CalcTotalResultsExpected();
}
else
return FALSE;
}
HRESULT CParamSets::ComputeGetResultHR(ULONG iResult)
{
/*
ULONG iStmt = 0;
if (iResult >= m_cTotalResultsExpected)
return E_INVALIDARG;
iStmt = m_prgResultMap[iResult];
// The very first GetResult() call returns S_OK and is basically a no-op unless Execute() fails.
if (iResult == 0)
return S_OK;
// If this statement is filling out params and has streams, then expect DB_E_OBJECTOPEN
if (iStmt < m_ceSQLStmts && m_rgeSQLStmts[iStmt] == ERPCSELECTOUT &&
m_prgStmtInfo[iStmt].fHasStreamBinding == TRUE)
return DB_E_OBJECTOPEN;
*/
return S_OK;
}
BOOL CParamSets::IsResultProducing(ULONG iStmt)
{
// Don't over-run array
if (!COMPARE(iStmt <= m_ceSQLStmts-1, TRUE))
return FALSE;
switch (m_rgeSQLStmts[iStmt])
{
// Insert stmts always return a result (count of rows affected) if there are not multiple
// paramsets or if they are the only statement in the batch, otherwise they do not return a result.
case EINSERT:
if (m_dbParams.cParamSets > 1 && m_ceSQLStmts > 1)
return FALSE;
else
return TRUE;
// Select stmts always return a result (rowset)
case ESELECT:
return TRUE;
case ERPCSELECTOUT:
// Output params with no stream binding don't produce a result
if (!m_prgStmtInfo[iStmt].fHasStreamBinding)
return FALSE;
// Output params with stream bindings in consecutive order only count as one result
if (iStmt > 0 && m_rgeSQLStmts[iStmt-1] == ERPCSELECTOUT && m_prgStmtInfo[iStmt-1].fHasStreamBinding)
return FALSE;
return TRUE;
default:
//Need to add code to deal with any other enum values
ASSERT(FALSE);
}
return FALSE;
}
ULONG CParamSets::CalcResultGroups()
{
ULONG cResGroups=0;
for (ULONG iStmt = 0; iStmt < m_ceSQLStmts; iStmt++)
if (IsResultProducing(iStmt))
cResGroups++;
return cResGroups;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Test Case Section
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// {{ TCW_TEST_CASE_MAP(TCGetResult_Rowset)
//--------------------------------------------------------------------
// @class All Purpose GetResult Tests
//
class TCGetResult_Rowset : public CTestBase {
public:
// @cmember Static array of variations
DECLARE_TEST_CASE_DATA();
public:
// {{ TCW_DECLARE_FUNCS
// @cmember Execution Routine
DECLARE_TEST_CASE_FUNCS(TCGetResult_Rowset,CTestBase);
// }} TCW_DECLARE_FUNCS_END
//@cmember Performs thorough valid tests on the given
//multiple result generating command in rMultRes
int TestValidMultResults(CMultResults& rMultRes, //Object to test
IID* rgRiidGetResult, //array of riids to pass to GetResult
REFIID riidExecute = IID_IMultipleResults); //riid to pass to Execute
// @cmember Initialization Routine
virtual BOOL Init();
// @cmember Termination Routine
virtual BOOL Terminate();
// {{ TCW_TESTVARS()
// @cmember Batch - insert, update, delete, update
int Variation_1();
// @cmember Batch - select, select, select
int Variation_2();
// @cmember Batch - select, insert, update, delete
int Variation_3();
// @cmember Batch - insert, update, delete, select
int Variation_4();
// @cmember Batch - select, insert, select
int Variation_5();
// @cmember Multiple ParamSets - select
int Variation_6();
// @cmember Multiple ParamSets - Insert
int Variation_7();
// @cmember Single - select
int Variation_8();
// @cmember Single - insert
int Variation_9();
// @cmember Batch - select, insert, delete; Ask for IID_IRowset on Execute
int Variation_10();
// @cmember Batch - insert, select, delete; Ask for IID_IRowset on Execute
int Variation_11();
// @cmember IMultipleResults AddRef(
int Variation_12();
// @cmember S_OK - riid == IAccessor
int Variation_13();
// @cmember S_OK - riid == IColumnsInfo
int Variation_14();
// @cmember S_OK - riid == IConverType
int Variation_15();
// @cmember S_OK - riid == IRowset
int Variation_16();
// @cmember S_OK - riid == IRowsetInfo
int Variation_17();
// @cmember S_OK - riid == IUnknown
int Variation_18();
// @cmember E_NOINTERFACE - riid == IID_IMultipleResults
int Variation_19();
// @cmember E_NOINTERFACE - riid == IRowsetUpdate
int Variation_20();
// @cmember DB_E_NOAGGREGATION - Valid pUnkOuter
int Variation_21();
// @cmember DB_E_OBJECTOPEN - Rowset with Open Rowset without support for multiple concurrent results
int Variation_22();
// @cmember E_INVALIDARG - lResultFlag is invalid
int Variation_23();
// @cmember riid == IID_NULL, rowset returning results
int Variation_24();
// @cmember riid == IID_NULL, Non rowset returning results
int Variation_25();
// @cmember ppRowset = NULL, rowset returning results
int Variation_26();
// @cmember ppRowset != NULL, Non rowset returning results
int Variation_27();
// @cmember pcRowsAffected == NULL, rowset returning result
int Variation_28();
// @cmember pcRowsAffected == NULL, Non rowset returning result
int Variation_29();
// @cmember Multiple Executions of same command open at same time
int Variation_30();
// @cmember Select, insert, select - RestartPosition on first and last select
int Variation_31();
// @cmember DB_S_NORESULT - Call after receiving DB_S_NORESULT once
int Variation_32();
// @cmember DBPROP_IRowsetLocate - insert, update, delete
int Variation_33();
// @cmember DBPROP_IRowsetLocate - insert, select, delete
int Variation_34();
// @cmember DBPROP_IRowsetLocate - insert, select, select
int Variation_35();
// @cmember DBPROP_CANHOLDROWS
int Variation_36();
// @cmember E_NOINTERFACE - IID_IMultipleResults on IOpenRowset::OpenRowset
int Variation_37();
// @cmember E_NOINTERFACE - IID_IMultipleResults on IDBSchemaRowset::GetRowset
int Variation_38();
// @cmember Select with empty rowset, mixed with poulated rowsets
int Variation_39();
// @cmember Release IMultipleResults while Rowset open
int Variation_40();
// @cmember Rowset creation failure do to E_NOINTERFACE
int Variation_41();
// @cmember Rowset creation failure due to non forward only cursor
int Variation_42();
// @cmember Multiple ParamSets in a batch - select, insert, select
int Variation_43();
// @cmember Multiple ParamSets in a batch - insert, select, insert
int Variation_44();
// @cmember Multiple ParamSets in a batch - select, select, select
int Variation_45();
// @cmember single select, RestartPosition -- DB_S_COMMANDREEXECUTED
int Variation_46();
// @cmember S_OK - Select on 2nd command while processing GetResult on first command
int Variation_47();
// @cmember S_OK - Single select, ask for IID_IRowsetScroll
int Variation_48();
// @cmember Aggregated batch - select, select, select
int Variation_49();
// @cmember Aggregated Result - Select, Select, Select
int Variation_50();
// @cmember DBPROP_IMultipleResults - Execute with IID_IUnknown but DBPROP_IMultipleResults
int Variation_51();
// @cmember DB_E_INTEGRITYVIOLATION: Batch - select, insert, select. Fail insert.
int Variation_52();
// @cmember DB_E_NOAGGREGATION: Aggregated Result asking for IID != IID_IUnknown
int Variation_53();
// @cmember S_OK: IMultipleResults with compute by clause
int Variation_54();
// @cmember DBPROP_SKIPROWCOUNTRESULTS (default): Ask for same type of object.
int Variation_55();
// @cmember DBPROP_SKIPROWCOUNTRESULTS (default): Ask for mixed types of objects.
int Variation_56();
// @cmember DBPROP_SKIPROWCOUNTRESULTS (true): Ask for same type of object.
int Variation_57();
// @cmember DBPROP_SKIPROWCOUNTRESULTS (true): Ask for mixed types of objects.
int Variation_58();
// @cmember DBPROP_IRow (true) : Get ROW objs
int Variation_59();
// @cmember DBPROP_IRow (true) : Set as optional and flag = ROWSET
int Variation_60();
// @cmember DBPROP_IRow (true) : Set as required and flag = ROWSET
int Variation_61();
// }} TCW_TESTVARS_END
};
// {{ TCW_TESTCASE(TCGetResult_Rowset)
#define THE_CLASS TCGetResult_Rowset
BEG_TEST_CASE(TCGetResult_Rowset, CTestBase, L"All Purpose GetResult Tests")
TEST_VARIATION(1, L"Batch - insert, update, delete, update")
TEST_VARIATION(2, L"Batch - select, select, select")
TEST_VARIATION(3, L"Batch - select, insert, update, delete")
TEST_VARIATION(4, L"Batch - insert, update, delete, select")
TEST_VARIATION(5, L"Batch - select, insert, select")
TEST_VARIATION(6, L"Multiple ParamSets - select")
TEST_VARIATION(7, L"Multiple ParamSets - Insert")
TEST_VARIATION(8, L"Single - select")
TEST_VARIATION(9, L"Single - insert")
TEST_VARIATION(10, L"Batch - select, insert, delete; Ask for IID_IRowset on Execute")
TEST_VARIATION(11, L"Batch - insert, select, delete; Ask for IID_IRowset on Execute")
TEST_VARIATION(12, L"IMultipleResults AddRef(")
TEST_VARIATION(13, L"S_OK - riid == IAccessor")
TEST_VARIATION(14, L"S_OK - riid == IColumnsInfo")
TEST_VARIATION(15, L"S_OK - riid == IConverType")
TEST_VARIATION(16, L"S_OK - riid == IRowset")
TEST_VARIATION(17, L"S_OK - riid == IRowsetInfo")
TEST_VARIATION(18, L"S_OK - riid == IUnknown")
TEST_VARIATION(19, L"E_NOINTERFACE - riid == IID_IMultipleResults")
TEST_VARIATION(20, L"E_NOINTERFACE - riid == IRowsetUpdate")
TEST_VARIATION(21, L"DB_E_NOAGGREGATION - Valid pUnkOuter")
TEST_VARIATION(22, L"DB_E_OBJECTOPEN - Rowset with Open Rowset without support for multiple concurrent results")
TEST_VARIATION(23, L"E_INVALIDARG - lResultFlag is invalid")
TEST_VARIATION(24, L"riid == IID_NULL, rowset returning results")
TEST_VARIATION(25, L"riid == IID_NULL, Non rowset returning results")
TEST_VARIATION(26, L"ppRowset = NULL, rowset returning results")
TEST_VARIATION(27, L"ppRowset != NULL, Non rowset returning results")
TEST_VARIATION(28, L"pcRowsAffected == NULL, rowset returning result")
TEST_VARIATION(29, L"pcRowsAffected == NULL, Non rowset returning result")
TEST_VARIATION(30, L"Multiple Executions of same command open at same time")
TEST_VARIATION(31, L"Select, insert, select - RestartPosition on first and last select")
TEST_VARIATION(32, L"DB_S_NORESULT - Call after receiving DB_S_NORESULT once")
TEST_VARIATION(33, L"DBPROP_IRowsetLocate - insert, update, delete")
TEST_VARIATION(34, L"DBPROP_IRowsetLocate - insert, select, delete")
TEST_VARIATION(35, L"DBPROP_IRowsetLocate - insert, select, select")
TEST_VARIATION(36, L"DBPROP_CANHOLDROWS")
TEST_VARIATION(37, L"E_NOINTERFACE - IID_IMultipleResults on IOpenRowset::OpenRowset")
TEST_VARIATION(38, L"E_NOINTERFACE - IID_IMultipleResults on IDBSchemaRowset::GetRowset")
TEST_VARIATION(39, L"Select with empty rowset, mixed with poulated rowsets")
TEST_VARIATION(40, L"Release IMultipleResults while Rowset open")
TEST_VARIATION(41, L"Rowset creation failure do to E_NOINTERFACE")
TEST_VARIATION(42, L"Rowset creation failure due to non forward only cursor")
TEST_VARIATION(43, L"Multiple ParamSets in a batch - select, insert, select")
TEST_VARIATION(44, L"Multiple ParamSets in a batch - insert, select, insert")
TEST_VARIATION(45, L"Multiple ParamSets in a batch - select, select, select")
TEST_VARIATION(46, L"single select, RestartPosition -- DB_S_COMMANDREEXECUTED")
TEST_VARIATION(47, L"S_OK - Select on 2nd command while processing GetResult on first command")
TEST_VARIATION(48, L"S_OK - Single select, ask for IID_IRowsetScroll")
TEST_VARIATION(49, L"Aggregated batch - select, select, select")
TEST_VARIATION(50, L"Aggregated Result - Select, Select, Select")
TEST_VARIATION(51, L"DBPROP_IMultipleResults - Execute with IID_IUnknown but DBPROP_IMultipleResults")
TEST_VARIATION(52, L"DB_E_INTEGRITYVIOLATION: Batch - select, insert, select. Fail insert.")
TEST_VARIATION(53, L"DB_E_NOAGGREGATION: Aggregated Result asking for IID != IID_IUnknown")
TEST_VARIATION(54, L"S_OK: IMultipleResults with compute by clause")
TEST_VARIATION(55, L"DBPROP_SKIPROWCOUNTRESULTS (default): Ask for same type of object.")
TEST_VARIATION(56, L"DBPROP_SKIPROWCOUNTRESULTS (default): Ask for mixed types of objects.")
TEST_VARIATION(57, L"DBPROP_SKIPROWCOUNTRESULTS (true): Ask for same type of object.")
TEST_VARIATION(58, L"DBPROP_SKIPROWCOUNTRESULTS (true): Ask for mixed types of objects.")
TEST_VARIATION(59, L"DBPROP_IRow (true) : Get ROW objs")
TEST_VARIATION(60, L"DBPROP_IRow (true) : Set as optional and flag = ROWSET")
TEST_VARIATION(61, L"DBPROP_IRow (true) : Set as required and flag = ROWSET")
END_TEST_CASE()
#undef THE_CLASS
// }} TCW_TESTCASE_END
// }} TCW_TEST_CASE_MAP_END
// {{ TCW_TEST_CASE_MAP(TCTxn)
//--------------------------------------------------------------------
// @class Tests Rowset behavior upon ending aTransaction
//
class TCTxn : public CTestBase {
private:
// @cmember Static array of variations
DECLARE_TEST_CASE_DATA();
public:
// {{ TCW_DECLARE_FUNCS
// @cmember Execution Routine
DECLARE_TEST_CASE_FUNCS(TCTxn,CTestBase);
// }} TCW_DECLARE_FUNCS_END
//@cmember Flag indicatign preservation of rowset on commit
BOOL m_fCommitPreserve;
//@cmember Flag indicatign preservation of rowset on commit
BOOL m_fAbortPreserve;
//@cmember Helper function to do all zombie testing for this testcase
int TCTxn::TestTxn(ETXN eTxn, BOOL fRetaining);
// @cmember Initialization Routine
virtual BOOL Init();
// @cmember Termination Routine
virtual BOOL Terminate();
// {{ TCW_TESTVARS()
// @cmember Commit Retaining
int Variation_1();
// @cmember Commit NonRetaining
int Variation_2();
// @cmember Abort Retaining
int Variation_3();
// @cmember Abort NonRetaining
int Variation_4();
// }} TCW_TESTVARS_END
};
// {{ TCW_TESTCASE(TCTxn)
#define THE_CLASS TCTxn
BEG_TEST_CASE(TCTxn, CTestBase, L"Tests Rowset behavior upon ending aTransaction")
TEST_VARIATION(1, L"Commit Retaining")
TEST_VARIATION(2, L"Commit NonRetaining")
TEST_VARIATION(3, L"Abort Retaining")
TEST_VARIATION(4, L"Abort NonRetaining")
END_TEST_CASE()
#undef THE_CLASS
// }} TCW_TESTCASE_END
// }} TCW_TEST_CASE_MAP_END
// }} END_DECLARE_TEST_CASES()
////////////////////////////////////////////////////////////////////////
// Copying Test Cases to make duplicate ones.
//
////////////////////////////////////////////////////////////////////////
#define COPY_TEST_CASE(theClass, baseClass) \
class theClass : public baseClass \
{ \
public: \
static const WCHAR m_wszTestCaseName[]; \
DECLARE_TEST_CASE_FUNCS(theClass, baseClass); \
}; \
const WCHAR theClass::m_wszTestCaseName[] = { L#theClass }; \
#define TEST_CASE_WITH_PARAM(iCase, theClass, param) \
case iCase: \
pCTestCase = new theClass(NULL); \
((theClass*)pCTestCase)->SetTestCaseParam(param); \
pCTestCase->SetOwningMod(iCase-1, pCThisTestModule); \
return pCTestCase;
COPY_TEST_CASE(TCGetResult_Row, TCGetResult_Rowset)
#if 0
// {{ TCW_TESTMODULE(ThisModule)
TEST_MODULE(2, ThisModule, gwszModuleDescrip)
TEST_CASE(1, TCGetResult_Rowset)
TEST_CASE(2, TCTxn)
END_TEST_MODULE()
// }} TCW_TESTMODULE_END
#else
TEST_MODULE(3, ThisModule, gwszModuleDescrip)
TEST_CASE_WITH_PARAM(1, TCGetResult_Rowset, TC_Rowset)
TEST_CASE_WITH_PARAM(2, TCGetResult_Row, TC_Row)
TEST_CASE(3, TCTxn)
END_TEST_MODULE()
#endif
// {{ TCW_TC_PROTOTYPE(TCGetResult_Rowset)
//*-----------------------------------------------------------------------
//| Test Case: TCGetResult_Rowset - All Purpose GetResult Tests
//| Created: 09/22/96
//*-----------------------------------------------------------------------
//--------------------------------------------------------------------
// @mfunc TestCase Initialization Routine
//
// @rdesc TRUE or FALSE
//
BOOL TCGetResult_Rowset::Init()
{
// {{ TCW_INIT_BASECLASS_CHECK
return CTestBase::Init();
// }}
}
//--------------------------------------------------------------------
// @mfunc Does valid testing of IMultipleResults
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCGetResult_Rowset::TestValidMultResults(CMultResults& rMultRes,
IID* rgRiidGetResult,
REFIID riidExecute)
{
//Generate the result(s)
if (CHECK(rMultRes.SetAndExecute(riidExecute), S_OK))
//Make sure they are correct, specifying we haven't
//processed any of them ourselves already
if (CHECK(rMultRes.ProcessAllResults(0, riidExecute, rgRiidGetResult), S_OK))
return TEST_PASS;
//Problems!
return TEST_FAIL;
}
// {{ TCW_VAR_PROTOTYPE(1)
//*-----------------------------------------------------------------------
// @mfunc Batch - insert, update, delete, update
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCGetResult_Rowset::Variation_1()
{
CBatch oBatch(m_pIDBCreateCommand,
m_pICommandText,
m_pSelectTable,
m_pChangeTable);
ESQLSTMT rgeSQLStmts[] = {
EINSERT,
EUPDATE,
EDELETE,
EUPDATE
};
const ULONG ceSQLStmts = sizeof(rgeSQLStmts) / sizeof(ESQLSTMT);
DECL_FLAGSANDIIDS(ceSQLStmts)
//Initialize batch statement with the proper SQL for this variation
if (!oBatch.FInit(ceSQLStmts, rgeSQLStmts, rgFlag))
return TEST_FAIL;
//Test that all results are correct
return TestValidMultResults(oBatch, rgIID);
}
// }}
// {{ TCW_VAR_PROTOTYPE(2)
//*-----------------------------------------------------------------------
// @mfunc Batch - select, select, select
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCGetResult_Rowset::Variation_2()
{
CBatch oBatch(m_pIDBCreateCommand,
m_pICommandText,
m_pSelectTable,
m_pChangeTable);
ESQLSTMT rgeSQLStmts[] = {
ESELECT,
ESELECT,
ESELECT
};
const ULONG ceSQLStmts = sizeof(rgeSQLStmts) / sizeof(ESQLSTMT);
DECL_FLAGSANDIIDS(ceSQLStmts)
//Initialize batch statement with the proper SQL for this variation
if (!oBatch.FInit(ceSQLStmts, rgeSQLStmts, rgFlag))
return TEST_FAIL;
//Test that all results are correct
return TestValidMultResults(oBatch, rgIID);
}
// }}
// {{ TCW_VAR_PROTOTYPE(3)
//*-----------------------------------------------------------------------
// @mfunc Batch - select, insert, update, delete
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCGetResult_Rowset::Variation_3()
{
CBatch oBatch(m_pIDBCreateCommand,
m_pICommandText,
m_pSelectTable,
m_pChangeTable);
ESQLSTMT rgeSQLStmts[] = {
ESELECT,
EINSERT,
EUPDATE,
EDELETE
};
const ULONG ceSQLStmts = sizeof(rgeSQLStmts) / sizeof(ESQLSTMT);
DECL_FLAGSANDIIDS(ceSQLStmts)
for(i=0; i<ceSQLStmts; i++)
rgFlag[i] = DBRESULTFLAG_DEFAULT;
//Initialize batch statement with the proper SQL for this variation
if (!oBatch.FInit(ceSQLStmts, rgeSQLStmts, rgFlag))
return TEST_FAIL;
//Test that all results are correct
return TestValidMultResults(oBatch, rgIID);
}
// }}
// {{ TCW_VAR_PROTOTYPE(4)
//*-----------------------------------------------------------------------
// @mfunc Batch - insert, update, delete, select
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCGetResult_Rowset::Variation_4()
{
CBatch oBatch(m_pIDBCreateCommand,
m_pICommandText,
m_pSelectTable,
m_pChangeTable);
ESQLSTMT rgeSQLStmts[] = {
EINSERT,
EUPDATE,
EDELETE,
ESELECT
};
const ULONG ceSQLStmts = sizeof(rgeSQLStmts) / sizeof(ESQLSTMT);
DECL_FLAGSANDIIDS(ceSQLStmts)
//Initialize batch statement with the proper SQL for this variation
if (!oBatch.FInit(ceSQLStmts, rgeSQLStmts, rgFlag))
return TEST_FAIL;
//Test that all results are correct
return TestValidMultResults(oBatch, rgIID);
}
// }}
// {{ TCW_VAR_PROTOTYPE(5)
//*-----------------------------------------------------------------------
// @mfunc Batch - select, insert, select
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCGetResult_Rowset::Variation_5()
{
CBatch oBatch(m_pIDBCreateCommand,
m_pICommandText,
m_pSelectTable,
m_pChangeTable);
ESQLSTMT rgeSQLStmts[] = {
ESELECT,
EINSERT,
ESELECT
};
const ULONG ceSQLStmts = sizeof(rgeSQLStmts) / sizeof(ESQLSTMT);
DECL_FLAGSANDIIDS(ceSQLStmts)
//Initialize batch statement with the proper SQL for this variation
if (!oBatch.FInit(ceSQLStmts, rgeSQLStmts, rgFlag))
return TEST_FAIL;
//Test that all results are correct
return TestValidMultResults(oBatch, rgIID);
}
// }}
// {{ TCW_VAR_PROTOTYPE(6)
//*-----------------------------------------------------------------------
// @mfunc Multiple ParamSets - select
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCGetResult_Rowset::Variation_6()
{
CParamSets oParamSets(5, //Use five paramter sets
m_pIDBCreateCommand,
m_pICommandText,
m_pSelectTable,
m_pChangeTable);
ESQLSTMT rgeSQLStmts[] = {
ESELECT
};
const ULONG ceSQLStmts = sizeof(rgeSQLStmts) / sizeof(ESQLSTMT);
if (!g_bMultipleParamSets)
{
odtLog << "Multiple parameter sets are not supported \n";
return TEST_SKIPPED;
}
DECL_FLAGSANDIIDS(5)
//Setup IIDs and Flags to use.
rgFlag[0] = ISROWSET ? DBRESULTFLAG_DEFAULT : DBRESULTFLAG_DEFAULT;
rgIID[0] = ISROWSET ? IID_IUnknown : IID_IConvertType;
rgFlag[1] = ISROWSET ? DBRESULTFLAG_DEFAULT : DBRESULTFLAG_ROW;
rgIID[1] = ISROWSET ? IID_IRowset : IID_IGetSession;
rgFlag[2] = ISROWSET ? DBRESULTFLAG_DEFAULT : DBRESULTFLAG_ROWSET;
rgIID[2] = ISROWSET ? IID_IRowsetInfo : IID_IRowsetInfo;
rgFlag[3] = ISROWSET ? DBRESULTFLAG_DEFAULT : DBRESULTFLAG_DEFAULT;
rgIID[3] = ISROWSET ? IID_IConvertType : IID_IRow;
rgFlag[4] = ISROWSET ? DBRESULTFLAG_DEFAULT : DBRESULTFLAG_ROW;
rgIID[4] = ISROWSET ? IID_IUnknown : IID_IUnknown;
//Initialize batch statement with the proper SQL for this variation
if (!oParamSets.FInit(ceSQLStmts, rgeSQLStmts, rgFlag, NUMELEM(rgFlag)))
return TEST_FAIL;
//Test that all results are correct
return TestValidMultResults(oParamSets, rgIID);
}
// }}
// {{ TCW_VAR_PROTOTYPE(7)
//*-----------------------------------------------------------------------
// @mfunc Multiple ParamSets - Insert
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCGetResult_Rowset::Variation_7()
{
CParamSets oParamSets(8, //Use 8 paramter sets
m_pIDBCreateCommand,
m_pICommandText,
m_pSelectTable,
m_pChangeTable);
ESQLSTMT rgeSQLStmts[] = {
EINSERT
};
const ULONG ceSQLStmts = sizeof(rgeSQLStmts) / sizeof(ESQLSTMT);
if (!g_bMultipleParamSets)
{
odtLog << "Multiple parameter sets are not supported \n";
return TEST_SKIPPED;
}
DECL_FLAGSANDIIDS(8)
//Setup IIDs and Flags to use.
rgFlag[0] = ISROWSET ? DBRESULTFLAG_DEFAULT : DBRESULTFLAG_DEFAULT;
rgIID[0] = ISROWSET ? IID_IAccessor : IID_IColumnsInfo;
rgFlag[1] = ISROWSET ? DBRESULTFLAG_DEFAULT : DBRESULTFLAG_ROW;
rgIID[1] = ISROWSET ? IID_IRowset : IID_IGetSession;
rgFlag[2] = ISROWSET ? DBRESULTFLAG_DEFAULT : DBRESULTFLAG_ROWSET;
rgIID[2] = ISROWSET ? IID_IRowsetInfo : IID_IRowsetInfo;
rgFlag[3] = ISROWSET ? DBRESULTFLAG_DEFAULT : DBRESULTFLAG_DEFAULT;
rgIID[3] = ISROWSET ? IID_IConvertType : IID_IRow;
rgFlag[4] = ISROWSET ? DBRESULTFLAG_DEFAULT : DBRESULTFLAG_ROW;
rgIID[4] = ISROWSET ? IID_IUnknown : IID_IUnknown;
rgFlag[5] = ISROWSET ? DBRESULTFLAG_DEFAULT : DBRESULTFLAG_ROWSET;
rgIID[5] = ISROWSET ? IID_IUnknown : IID_IUnknown;
rgFlag[6] = ISROWSET ? DBRESULTFLAG_DEFAULT : DBRESULTFLAG_ROW;
rgIID[6] = ISROWSET ? IID_IAccessor : IID_IConvertType;
rgFlag[7] = ISROWSET ? DBRESULTFLAG_DEFAULT : DBRESULTFLAG_DEFAULT;
rgIID[7] = ISROWSET ? IID_IConvertType : IID_IUnknown;
//Initialize batch statement with the proper SQL for this variation
if (!oParamSets.FInit(ceSQLStmts, rgeSQLStmts, rgFlag, NUMELEM(rgFlag)))
return TEST_FAIL;
//Test that all results are correct.
return TestValidMultResults(oParamSets, rgIID);
}
// }}
// {{ TCW_VAR_PROTOTYPE(8)
//*-----------------------------------------------------------------------
// @mfunc Single - select
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCGetResult_Rowset::Variation_8()
{
CBatch oSingle(m_pIDBCreateCommand,
m_pICommandText,
m_pSelectTable,
m_pChangeTable);
ESQLSTMT rgeSQLStmts[] = {
ESELECT,
};
const ULONG ceSQLStmts = sizeof(rgeSQLStmts) / sizeof(ESQLSTMT);
DECL_FLAGSANDIIDS(ceSQLStmts)
//Initialize batch statement with the proper SQL for this variation
if (!oSingle.FInit(ceSQLStmts, rgeSQLStmts, rgFlag))
return TEST_FAIL;
//Test that all results are correct
return TestValidMultResults(oSingle, rgIID);
}
// }}
// {{ TCW_VAR_PROTOTYPE(9)
//*-----------------------------------------------------------------------
// @mfunc Single - insert
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCGetResult_Rowset::Variation_9()
{
CBatch oBatch(m_pIDBCreateCommand,
m_pICommandText,
m_pSelectTable,
m_pChangeTable);
ESQLSTMT rgeSQLStmts[] = {
EINSERT,
};
const ULONG ceSQLStmts = sizeof(rgeSQLStmts) / sizeof(ESQLSTMT);
DECL_FLAGSANDIIDS(ceSQLStmts)
//Initialize batch statement with the proper SQL for this variation
if (!oBatch.FInit(ceSQLStmts, rgeSQLStmts, rgFlag))
return TEST_FAIL;
//Test that all results are correct
return TestValidMultResults(oBatch, rgIID);
}
// }}
// {{ TCW_VAR_PROTOTYPE(10)
//*-----------------------------------------------------------------------
// @mfunc Batch - select, insert, delete; Ask for IID_IRowset on Execute
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCGetResult_Rowset::Variation_10()
{
CBatch oBatch(m_pIDBCreateCommand,
m_pICommandText,
m_pSelectTable,
m_pChangeTable);
ESQLSTMT rgeSQLStmts[] = {
ESELECT,
EINSERT,
EDELETE
};
const ULONG ceSQLStmts = sizeof(rgeSQLStmts) / sizeof(ESQLSTMT);
DECL_FLAGSANDIIDS(ceSQLStmts)
//Initialize batch statement with the proper SQL for this variation
if (!oBatch.FInit(ceSQLStmts, rgeSQLStmts, rgFlag))
return TEST_FAIL;
//Test that all results are correct
//All IIDs in rgIID are initialized to IID_IRowset.
return TestValidMultResults(oBatch, rgIID, ISROWSET ? IID_IRowset : IID_IRow);
}
// }}
// {{ TCW_VAR_PROTOTYPE(11)
//*-----------------------------------------------------------------------
// @mfunc Batch - insert, select, delete; Ask for IID_IRowset on Execute
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCGetResult_Rowset::Variation_11()
{
CBatch oBatch(m_pIDBCreateCommand,
m_pICommandText,
m_pSelectTable,
m_pChangeTable);
ESQLSTMT rgeSQLStmts[] = {
EINSERT,
ESELECT,
EDELETE
};
const ULONG ceSQLStmts = sizeof(rgeSQLStmts) / sizeof(ESQLSTMT);
DECL_FLAGSANDIIDS(ceSQLStmts)
//Initialize batch statement with the proper SQL for this variation
if (!oBatch.FInit(ceSQLStmts, rgeSQLStmts, rgFlag))
return TEST_FAIL;
//Test that all results are correct
//All IIDs in rgIID are initialized to IID_IRowset.
return TestValidMultResults(oBatch, rgIID, ISROWSET ? IID_IRowset : IID_IRow);
}
// }}
// {{ TCW_VAR_PROTOTYPE(12)
//*-----------------------------------------------------------------------
// @mfunc IMultipleResults AddRef(
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCGetResult_Rowset::Variation_12()
{
BOOL fResults = FALSE;
CMultResults * pMultResults = NULL;
//Get an IMultipleResults interface
if (CHECK(SetUpGetResult(&pMultResults), S_OK))
{
//Do a net ref count of zero
pMultResults->m_pIMultResults->AddRef();
pMultResults->m_pIMultResults->Release();
pMultResults->m_pIMultResults->AddRef();
pMultResults->m_pIMultResults->AddRef();
pMultResults->m_pIMultResults->Release();
pMultResults->m_pIMultResults->AddRef();
pMultResults->m_pIMultResults->Release();
pMultResults->m_pIMultResults->Release();
//Only count we are guaranteed of is 0, and we
//should be there right now
if (COMPARE(pMultResults->m_pIMultResults->Release(), 0))
{
fResults = TRUE;
pMultResults->m_pIMultResults = NULL;
}
delete pMultResults;
}
if (fResults)
return TEST_PASS;
else
return TEST_FAIL;
}
// }}
// {{ TCW_VAR_PROTOTYPE(13)
//*-----------------------------------------------------------------------
// @mfunc S_OK - riid == IAccessor
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCGetResult_Rowset::Variation_13()
{
CBatch oBatch(m_pIDBCreateCommand,
m_pICommandText,
m_pSelectTable,
m_pChangeTable);
ESQLSTMT rgeSQLStmts[] = {
EINSERT,
ESELECT,
EDELETE,
EUPDATE,
ESELECT,
ESELECT
};
const ULONG ceSQLStmts = sizeof(rgeSQLStmts) / sizeof(ESQLSTMT);
DECL_FLAGSANDIIDS(ceSQLStmts)
//Setup IIDs and Flags to use.
rgFlag[0] = ISROWSET ? DBRESULTFLAG_DEFAULT : DBRESULTFLAG_DEFAULT;
rgIID[0] = ISROWSET ? IID_IAccessor : IID_IRow;
rgFlag[1] = ISROWSET ? DBRESULTFLAG_DEFAULT : DBRESULTFLAG_ROW;
rgIID[1] = ISROWSET ? IID_IAccessor : IID_IColumnsInfo;
rgFlag[2] = ISROWSET ? DBRESULTFLAG_DEFAULT : DBRESULTFLAG_ROW;
rgIID[2] = ISROWSET ? IID_IAccessor : IID_IRowsetInfo;
rgFlag[3] = ISROWSET ? DBRESULTFLAG_DEFAULT : DBRESULTFLAG_DEFAULT;
rgIID[3] = ISROWSET ? IID_IAccessor : IID_IGetSession;
rgFlag[4] = ISROWSET ? DBRESULTFLAG_DEFAULT : DBRESULTFLAG_DEFAULT;
rgIID[4] = ISROWSET ? IID_IAccessor : IID_IRow;
rgFlag[5] = ISROWSET ? DBRESULTFLAG_DEFAULT : DBRESULTFLAG_ROW;
rgIID[5] = ISROWSET ? IID_IAccessor : IID_IUnknown;
//Initialize batch statement with the proper SQL for this variation
if (!oBatch.FInit(ceSQLStmts, rgeSQLStmts, rgFlag))
return TEST_FAIL;
//Verify we can get IID_IAccessor on all rowset returning results
return TestValidMultResults(oBatch, rgIID);
}
// }}
// {{ TCW_VAR_PROTOTYPE(14)
//*-----------------------------------------------------------------------
// @mfunc S_OK - riid == IColumnsInfo
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCGetResult_Rowset::Variation_14()
{
CBatch oBatch(m_pIDBCreateCommand,
m_pICommandText,
m_pSelectTable,
m_pChangeTable);
ESQLSTMT rgeSQLStmts[] = {
ESELECT,
ESELECT,
ESELECT,
EDELETE,
EINSERT
};
const ULONG ceSQLStmts = sizeof(rgeSQLStmts) / sizeof(ESQLSTMT);
DECL_FLAGSANDIIDS(ceSQLStmts)
//Setup IIDs and Flags to use.
//Change all IIDs to IID_IColumnsInfo.
for(i=0; i<ceSQLStmts; i++)
rgIID[i] = IID_IColumnsInfo;
rgFlag[0] = ISROWSET ? DBRESULTFLAG_DEFAULT : DBRESULTFLAG_ROW;
rgFlag[1] = ISROWSET ? DBRESULTFLAG_DEFAULT : DBRESULTFLAG_ROW;
rgFlag[2] = ISROWSET ? DBRESULTFLAG_DEFAULT : DBRESULTFLAG_ROW;
rgFlag[3] = ISROWSET ? DBRESULTFLAG_DEFAULT : DBRESULTFLAG_ROW;
rgFlag[4] = ISROWSET ? DBRESULTFLAG_DEFAULT : DBRESULTFLAG_ROW;
//Initialize batch statement with the proper SQL for this variation
if (!oBatch.FInit(ceSQLStmts, rgeSQLStmts, rgFlag))
return TEST_FAIL;
//Verify we can get IID_IColumnsInfo on all rowset returning results
return TestValidMultResults(oBatch, rgIID);
}
// }}
// {{ TCW_VAR_PROTOTYPE(15)
//*-----------------------------------------------------------------------
// @mfunc S_OK - riid == IConverType
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCGetResult_Rowset::Variation_15()
{
CBatch oBatch(m_pIDBCreateCommand,
m_pICommandText,
m_pSelectTable,
m_pChangeTable);
ESQLSTMT rgeSQLStmts[] = {
EINSERT,
ESELECT,
EDELETE,
ESELECT,
ESELECT
};
const ULONG ceSQLStmts = sizeof(rgeSQLStmts) / sizeof(ESQLSTMT);
DECL_FLAGSANDIIDS(ceSQLStmts)
//Change all IIDs to IID_IConvertType.
for(i=0; i<ceSQLStmts; i++)
rgIID[i] = IID_IConvertType;
rgFlag[0] = ISROWSET ? DBRESULTFLAG_DEFAULT : DBRESULTFLAG_ROW;
rgFlag[1] = ISROWSET ? DBRESULTFLAG_DEFAULT : DBRESULTFLAG_ROW;
rgFlag[2] = ISROWSET ? DBRESULTFLAG_DEFAULT : DBRESULTFLAG_ROW;
rgFlag[3] = ISROWSET ? DBRESULTFLAG_DEFAULT : DBRESULTFLAG_ROW;
rgFlag[4] = ISROWSET ? DBRESULTFLAG_DEFAULT : DBRESULTFLAG_ROW;
//Initialize batch statement with the proper SQL for this variation
if (!oBatch.FInit(ceSQLStmts, rgeSQLStmts, rgFlag))
return TEST_FAIL;
//Verify we can get IID_IConvertType on all rowset returning results
return TestValidMultResults(oBatch, rgIID);
}
// }}
// {{ TCW_VAR_PROTOTYPE(16)
//*-----------------------------------------------------------------------
// @mfunc S_OK - riid == IRowset
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCGetResult_Rowset::Variation_16()
{
CBatch oBatch(m_pIDBCreateCommand,
m_pICommandText,
m_pSelectTable,
m_pChangeTable);
ESQLSTMT rgeSQLStmts[] = {
ESELECT,
ESELECT,
EDELETE
};
const ULONG ceSQLStmts = sizeof(rgeSQLStmts) / sizeof(ESQLSTMT);
DECL_FLAGSANDIIDS(ceSQLStmts)
//Initialize batch statement with the proper SQL for this variation
if (!oBatch.FInit(ceSQLStmts, rgeSQLStmts, rgFlag))
return TEST_FAIL;
//Verify we can get IID_IRowset on all rowset returning results
return TestValidMultResults(oBatch, rgIID);
}
// }}
// {{ TCW_VAR_PROTOTYPE(17)
//*-----------------------------------------------------------------------
// @mfunc S_OK - riid == IRowsetInfo
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCGetResult_Rowset::Variation_17()
{
CBatch oBatch(m_pIDBCreateCommand,
m_pICommandText,
m_pSelectTable,
m_pChangeTable);
ESQLSTMT rgeSQLStmts[] = {
ESELECT,
ESELECT,
ESELECT,
ESELECT,
ESELECT,
ESELECT,
ESELECT,
ESELECT
};
const ULONG ceSQLStmts = sizeof(rgeSQLStmts) / sizeof(ESQLSTMT);
DECL_FLAGSANDIIDS(ceSQLStmts)
//Change IIDs and Flags. For the TC_Rowset case alternate
//between flags DEFAULT and ROWSET, and choose IID as IRowsetInfo.
//For the TC_Row case, alternate between a rowset and row.
if(ISROWSET)
{
for(i=0; i<ceSQLStmts; i++)
{
if(i%2)
rgFlag[i] = DBRESULTFLAG_DEFAULT;
else
rgFlag[i] = DBRESULTFLAG_DEFAULT;
rgIID[i] = IID_IRowsetInfo;
}
}
else
{
for(i=0; i<ceSQLStmts; i++)
{
if(i%2)
{
rgFlag[i] = DBRESULTFLAG_DEFAULT;
rgIID[i] = IID_IRowsetInfo;
}
else
{
rgFlag[i] = DBRESULTFLAG_ROW;
rgIID[i] = IID_IConvertType;
}
}
}
//Initialize batch statement with the proper SQL for this variation
if (!oBatch.FInit(ceSQLStmts, rgeSQLStmts, rgFlag))
return TEST_FAIL;
//Verify we can get IID_IRowsetInfo on all rowset returning results
return TestValidMultResults(oBatch, rgIID);
}
// }}
// {{ TCW_VAR_PROTOTYPE(18)
//*-----------------------------------------------------------------------
// @mfunc S_OK - riid == IUnknown
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCGetResult_Rowset::Variation_18()
{
CBatch oBatch(m_pIDBCreateCommand,
m_pICommandText,
m_pSelectTable,
m_pChangeTable);
ESQLSTMT rgeSQLStmts[] = {
EINSERT,
ESELECT,
EDELETE,
ESELECT,
ESELECT,
ESELECT
};
const ULONG ceSQLStmts = sizeof(rgeSQLStmts) / sizeof(ESQLSTMT);
DECL_FLAGSANDIIDS(ceSQLStmts)
//Change all IIDs to IID_IUnknown.
for(i=0; i<ceSQLStmts; i++)
{
rgIID[i] = IID_IUnknown;
if(i%2)
rgFlag[i] = DBRESULTFLAG_DEFAULT;
}
//Initialize batch statement with the proper SQL for this variation
if (!oBatch.FInit(ceSQLStmts, rgeSQLStmts, rgFlag))
return TEST_FAIL;
//Verify we can get IID_IUnknown on all rowset returning results
return TestValidMultResults(oBatch, rgIID);
}
// }}
// {{ TCW_VAR_PROTOTYPE(19)
//*-----------------------------------------------------------------------
// @mfunc E_NOINTERFACE - riid == IID_IMultipleResults
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCGetResult_Rowset::Variation_19()
{
IRowset * pIRowset = (IRowset *)0x12345678; //Init so we know if it's nulled
IRow * pIRow = (IRow *)0x12345678;
BOOL fResults = FALSE;
CMultResults * pMultResults = NULL;
ESQLSTMT rgeSQLStmts[] = {
EINSERT,
ESELECT,
ESELECT
};
const ULONG ceSQLStmts = sizeof(rgeSQLStmts) / sizeof(ESQLSTMT);
DECL_FLAGSANDIIDS(ceSQLStmts)
//Get an IMultipleResults interface
if (CHECK(SetUpGetResult(&pMultResults, ceSQLStmts, rgeSQLStmts, rgFlag), S_OK))
{
//Do a successful call
if (CHECK(pMultResults->m_pIMultResults->GetResult(NULL,
rgFlag[0],
IID_NULL,
&pMultResults->m_cRowsGetResultAffected,
(IUnknown **)&pIRowset),
S_OK))
{
COMPARE(pIRowset, NULL);
COMPARE(pMultResults->m_cRowsGetResultAffected, 1);
if(pIRowset && (pIRowset != (IUnknown *)0x12345678))
pIRowset->Release();
pIRowset = (IRowset *)0x12345678;
//Try unsupported IID
if (CHECK(pMultResults->m_pIMultResults->GetResult(NULL,
rgFlag[1],
IID_IMultipleResults,
&pMultResults->m_cRowsGetResultAffected,
(IUnknown **)&pIRowset),
E_NOINTERFACE))
if ((pMultResults->CheckErrorOutParams(pIRowset))&&(COMPARE(pMultResults->m_cRowsGetResultAffected,-1)) )
{
//the current is lost. Now verify the next one
if(ISROWSET)
{
if (CHECK(pMultResults->m_pIMultResults->GetResult(NULL,
0,
IID_IRowset,
&pMultResults->m_cRowsGetResultAffected,
(IUnknown **)&pIRowset),
S_OK))
{
if (CHECK(pMultResults->VerifySelectRowset(IID_IRowset, pIRowset, TRUE), S_OK))
fResults = TRUE;
pIRowset->Release();
pIRowset = NULL;
}
}
else
{
if (CHECK(pMultResults->m_pIMultResults->GetResult(NULL,
DBRESULTFLAG_ROW,
IID_IRow,
&pMultResults->m_cRowsGetResultAffected,
(IUnknown **)&pIRow),
S_OK))
{
if (CHECK(pMultResults->VerifySelectRowset(IID_IRow, pIRow, FALSE), S_OK))
fResults = TRUE;
SAFE_RELEASE(pIRow);
}
}
}
}
}
//Cleanup from SetUpGetResult()
if (pMultResults)
{
pMultResults->ReleaseIMultipleResults();
delete pMultResults;
}
if (fResults)
return TEST_PASS;
else
return TEST_FAIL;
}
// }}
// {{ TCW_VAR_PROTOTYPE(20)
//*-----------------------------------------------------------------------
// @mfunc E_NOINTERFACE - riid == IRowsetUpdate
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCGetResult_Rowset::Variation_20()
{
IRowsetUpdate * pIRowUpdate = (IRowsetUpdate *)0x12345678;//Init so we know if it's nulled
IUnknown * pIUnknown = (IUnknown *)0x12345678; //Init so we know if it's nulled
BOOL fResults = FALSE;
CMultResults * pMultResults = NULL;
ESQLSTMT rgeSQLStmts[] = {
EINSERT,
ESELECT,
};
const ULONG ceSQLStmts = sizeof(rgeSQLStmts) / sizeof(ESQLSTMT);
DECL_FLAGSANDIIDS(ceSQLStmts)
//Get an IMultipleResults interface
if (CHECK(SetUpGetResult(&pMultResults, ceSQLStmts, rgeSQLStmts, rgFlag), S_OK))
{
if (CHECK(pMultResults->m_pIMultResults->GetResult(NULL,
rgFlag[0],
IID_IUnknown,
&pMultResults->m_cRowsGetResultAffected,
(IUnknown **)&pIUnknown), S_OK))
if ( (COMPARE(pIUnknown, NULL))&&(COMPARE(pMultResults->m_cRowsGetResultAffected, 1)) )
fResults = TRUE;
else if(pIUnknown && (pIUnknown != (IUnknown *)0x12345678))
pIUnknown->Release();
pIUnknown = (IUnknown *)0x12345678;
//Try unsupported IID
if (CHECK(pMultResults->m_pIMultResults->GetResult(NULL,
DBRESULTFLAG_DEFAULT,
IID_IRowsetUpdate,
&pMultResults->m_cRowsGetResultAffected,
(IUnknown **)&pIRowUpdate), E_NOINTERFACE))
{
if ((COMPARE(pIRowUpdate, NULL))&&(COMPARE(pMultResults->m_cRowsGetResultAffected, -1)) )
fResults &= TRUE;
else if(pIRowUpdate && (pIRowUpdate != (IRowsetUpdate *)0x12345678))
{
fResults = FALSE;
pIRowUpdate->Release();
}
}
//Now verify that we have no result, since current is lost
if (CHECK(pMultResults->m_pIMultResults->GetResult(NULL,
rgFlag[1],
IID_IUnknown,
&pMultResults->m_cRowsGetResultAffected,
(IUnknown **)&pIUnknown), DB_S_NORESULT))
if( (COMPARE(pIUnknown, NULL))&&(COMPARE(pMultResults->m_cRowsGetResultAffected, -1)) )
fResults &= TRUE;
}
if(pIUnknown && (pIUnknown!= (IUnknown *)0x12345678))
COMPARE(pIUnknown->Release(), 0);
//Cleanup from SetUpGetResult()
if (pMultResults)
{
pMultResults->ReleaseIMultipleResults();
delete pMultResults;
}
if (fResults)
return TEST_PASS;
else
return TEST_FAIL;
}
// }}
// {{ TCW_VAR_PROTOTYPE(21)
//*-----------------------------------------------------------------------
// @mfunc DB_E_NOAGGREGATION - Valid pUnkOuter
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCGetResult_Rowset::Variation_21()
{
IUnknown * pIUnknown = INVALID(IUnknown *);
BOOL fResults = FALSE;
CMultResults * pMultResults = NULL;
//We are faking that this is a valid pointer
//for the purpose of pretending to aggregate.
//We should be able to pass this and just not
//do anything on the aggregated object to be safe.
IUnknown * pValidUnk = new CFakeUnk;
DECL_FLAGSANDIIDS(3)
if (!pValidUnk)
return TEST_FAIL;
//Get an IMultipleResults interface
if (CHECK(SetUpGetResult(&pMultResults), S_OK))
{
//Try "valid" punkouter
m_hr = pMultResults->m_pIMultResults->GetResult(pValidUnk,
rgFlag[0],
IID_IUnknown, //Must ask for IUnknown
&pMultResults->m_cRowsGetResultAffected,
(IUnknown **)&pIUnknown);
//Either return code is acceptable
if (m_hr == S_OK)
{
if(pIUnknown && (pIUnknown!=INVALID(IUnknown *)))
pIUnknown->Release();
pIUnknown = NULL;
//Make sure the rest of the results are right
fResults = CHECK(pMultResults->ProcessAllResults(1, IID_IMultipleResults, rgIID), S_OK);
}
if (m_hr == DB_E_NOAGGREGATION)
{
//Make sure parameters were nulled out on error
if (pMultResults->CheckErrorOutParams(pIUnknown))
fResults = TRUE;
//Provider should allow us to get next result on this error code
if (CHECK(pMultResults->ProcessAllResults(0, IID_IMultipleResults, rgIID), S_OK))
fResults &= TRUE;
else
fResults = FALSE;
}
if (pIUnknown &&(pIUnknown != INVALID(IUnknown *)))
pIUnknown->Release();
pIUnknown = NULL;
}
//Cleanup from SetUpGetResult()
if (pMultResults)
{
pMultResults->ReleaseIMultipleResults();
delete pMultResults;
}
if (pValidUnk)
delete pValidUnk;
if (fResults)
return TEST_PASS;
else
return TEST_FAIL;
}
// }}
// {{ TCW_VAR_PROTOTYPE(22)
//*-----------------------------------------------------------------------
// @mfunc DB_E_OBJECTOPEN - Rowset with Open Rowset without support for multiple concurrent results
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCGetResult_Rowset::Variation_22()
{
BOOL fResults = FALSE;
ULONG_PTR ulValue;
IUnknown * pFirstRowset = NULL;
IUnknown * pSecondRowset = NULL;
CBatch oBatch(m_pIDBCreateCommand,
m_pICommandText,
m_pSelectTable,
m_pChangeTable);
ESQLSTMT rgeSQLStmts[] = {
ESELECT,
ESELECT,
ESELECT
};
const ULONG ceSQLStmts = sizeof(rgeSQLStmts) / sizeof(ESQLSTMT);
DECL_FLAGSANDIIDS(ceSQLStmts)
if ((GetProperty(DBPROP_MULTIPLERESULTS, DBPROPSET_DATASOURCEINFO, m_pThisTestModule->m_pIUnknown, &ulValue)) &&
!(ulValue & DBPROPVAL_MR_CONCURRENT))
{
// Initialize batch statement with the proper SQL for this variation
if (!oBatch.FInit(ceSQLStmts, rgeSQLStmts, rgFlag))
return TEST_FAIL;
if (CHECK(oBatch.SetAndExecute(IID_IMultipleResults),S_OK))
{
//Open first rowset
if (CHECK(oBatch.m_pIMultResults->GetResult(NULL, rgFlag[0], rgIID[0],
NULL, (IUnknown **)&pFirstRowset), S_OK))
{
if (CHECK(oBatch.m_pIMultResults->GetResult(NULL, rgFlag[1],
rgIID[1],
&oBatch.m_cRowsGetResultAffected,
(IUnknown **)&pSecondRowset), DB_E_OBJECTOPEN))
if (oBatch.CheckErrorOutParams(pSecondRowset))
fResults = TRUE;
//now close the rowset object
pFirstRowset->Release();
pFirstRowset = NULL;
//Provider should allow us to get next result on this error code
if (CHECK(oBatch.ProcessAllResults(1, IID_IMultipleResults, rgIID), S_OK))
fResults &= TRUE;
else
fResults = FALSE;
}
if(pSecondRowset)
pSecondRowset->Release();
pSecondRowset = NULL;
if(pFirstRowset)
pFirstRowset->Release();
pFirstRowset = NULL;
//Clean up from SetAndExecute
oBatch.ReleaseIMultipleResults();
}
}
else
{
// Current results are supported, test is not applicable
odtLog << L"Current results are supported, test is not applicable.\n";
fResults = TEST_SKIPPED;
}
return fResults;
}
// }}
// {{ TCW_VAR_PROTOTYPE(23)
//*-----------------------------------------------------------------------
// @mfunc E_INVALIDARG - lResultFlag is invalid
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCGetResult_Rowset::Variation_23()
{
IRowset * pIRowset = INVALID(IRowset *);
BOOL fResults = FALSE;
CMultResults * pMultResults = NULL;
DECL_FLAGSANDIIDS(3)
//The only valid values for lResultFlag are - INVALID
// DBRESULTFLAG_DEFAULT = 0
// DBRESULTFLAG_ROWSET = 1
// DBRESULTFLAG_ROW = 2
//Get an IMultipleResults interface.
if (CHECK(SetUpGetResult(&pMultResults), S_OK))
if (CHECK(pMultResults->m_pIMultResults->GetResult(NULL,
3, //invalid lResultFlag
IID_IRowset,
&pMultResults->m_cRowsGetResultAffected,
(IUnknown **)&pIRowset),
E_INVALIDARG))
{
if (pMultResults->CheckErrorOutParams(pIRowset))
fResults = TRUE;
//In case provider is incorrectly giving us a rowset,
//release it so the open object doesn't hose the
//rest of our variations
if (pIRowset && pIRowset!=INVALID(IRowset *))
pIRowset->Release();
pIRowset = NULL;
//Provider should allow us to get next result on this error code
if (CHECK(pMultResults->ProcessAllResults(0, IID_IMultipleResults, rgIID), S_OK))
fResults &= TRUE;
else
fResults = FALSE;
}
if (pIRowset && pIRowset!=INVALID(IRowset *))
pIRowset->Release();
pIRowset = NULL;
//Cleanup from SetUpGetResult()
if (pMultResults)
{
pMultResults->ReleaseIMultipleResults();
delete pMultResults;
}
if (fResults)
return TEST_PASS;
else
return TEST_FAIL;
}
// }}
// {{ TCW_VAR_PROTOTYPE(24)
//*-----------------------------------------------------------------------
// @mfunc riid == IID_NULL, rowset returning results
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCGetResult_Rowset::Variation_24()
{
IRowset * pIRowset = INVALID(IRowset *);
//IRowset * pIRowset = NULL;
BOOL fResults = FALSE;
CMultResults * pMultResults = NULL;
ESQLSTMT rgeSQLStmts[] = {
ESELECT, //Start with rowset returning
EINSERT,
ESELECT
};
const ULONG ceSQLStmts = sizeof(rgeSQLStmts) / sizeof(ESQLSTMT);
DECL_FLAGSANDIIDS(ceSQLStmts)
//Get an IMultipleResults interface, use our own SQLStmts
if (CHECK(SetUpGetResult(&pMultResults, ceSQLStmts, rgeSQLStmts, rgFlag), S_OK))
{
if (CHECK(pMultResults->m_pIMultResults->GetResult(NULL,
rgFlag[0],
IID_NULL, //Test IID
&pMultResults->m_cRowsGetResultAffected,
(IUnknown **)&pIRowset),
S_OK))
{
//Check row count
if (COMPARE(pMultResults->IsGetResultRowsAffectedRight(0), TRUE))
//Interface must be nulled
if (COMPARE(pIRowset, NULL))
//Make sure the rest of the results are OK (we processed the first one already)
if (CHECK(pMultResults->ProcessAllResults(1, IID_IMultipleResults, rgIID), S_OK))
fResults = TRUE;
}
if((pIRowset)&&(pIRowset!=INVALID(IRowset *)))
pIRowset->Release();
pIRowset = NULL;
}
//Cleanup from SetUpGetResult()
if (pMultResults)
{
pMultResults->ReleaseIMultipleResults();
delete pMultResults;
}
if (fResults)
return TEST_PASS;
else
return TEST_FAIL;
}
// }}
// {{ TCW_VAR_PROTOTYPE(25)
//*-----------------------------------------------------------------------
// @mfunc riid == IID_NULL, Non rowset returning results
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCGetResult_Rowset::Variation_25()
{
IRowset * pIRowset = INVALID(IRowset *);
BOOL fResults = FALSE;
CMultResults * pMultResults = NULL;
ESQLSTMT rgeSQLStmts[] = {
EINSERT, //Start with non rowset returning
ESELECT,
EINSERT
};
const ULONG ceSQLStmts = sizeof(rgeSQLStmts) / sizeof(ESQLSTMT);
DECL_FLAGSANDIIDS(ceSQLStmts)
//Get an IMultipleResults interface, use our own SQLStmts
if (CHECK(SetUpGetResult(&pMultResults, ceSQLStmts, rgeSQLStmts, rgFlag), S_OK))
if (CHECK(pMultResults->m_pIMultResults->GetResult(NULL,
rgFlag[0],
IID_NULL, //Test IID
&pMultResults->m_cRowsGetResultAffected,
(IUnknown **)&pIRowset),
S_OK))
//It should be just like an error, outparams nulled
if (COMPARE(pMultResults->IsGetResultRowsAffectedRight(0), TRUE))
//Make sure the rest of the results are OK (we processed the first one already)
if (CHECK(pMultResults->ProcessAllResults(1, IID_IMultipleResults, rgIID), S_OK))
fResults = TRUE;
if((pIRowset)&&(pIRowset!=INVALID(IRowset *)))
pIRowset->Release();
pIRowset = NULL;
//Cleanup from SetUpGetResult()
if (pMultResults)
{
pMultResults->ReleaseIMultipleResults();
delete pMultResults;
}
if (fResults)
return TEST_PASS;
else
return TEST_FAIL;
}
// }}
// {{ TCW_VAR_PROTOTYPE(26)
//*-----------------------------------------------------------------------
// @mfunc ppRowset = NULL, rowset returning results
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCGetResult_Rowset::Variation_26()
{
BOOL fResults = FALSE;
CMultResults * pMultResults = NULL;
ESQLSTMT rgeSQLStmts[] = {
ESELECT, //Start with rowset returning
EINSERT,
ESELECT
};
const ULONG ceSQLStmts = sizeof(rgeSQLStmts) / sizeof(ESQLSTMT);
DECL_FLAGSANDIIDS(ceSQLStmts)
//Get an IMultipleResults interface, use our own SQLStmts
if (CHECK(SetUpGetResult(&pMultResults, ceSQLStmts, rgeSQLStmts, rgFlag), S_OK))
if (CHECK(pMultResults->m_pIMultResults->GetResult(NULL,
rgFlag[0],
rgIID[0],
&pMultResults->m_cRowsGetResultAffected,
NULL), //Test NULL ppRowset
S_OK))
//Check row count
if (COMPARE(pMultResults->IsGetResultRowsAffectedRight(0), TRUE))
//Make sure the rest of the results are OK (we processed the first one already)
if (CHECK(pMultResults->ProcessAllResults(1, IID_IMultipleResults, rgIID), S_OK))
fResults = TRUE;
//Cleanup from SetUpGetResult()
if (pMultResults)
{
pMultResults->ReleaseIMultipleResults();
delete pMultResults;
}
if (fResults)
return TEST_PASS;
else
return TEST_FAIL;
}
// }}
// {{ TCW_VAR_PROTOTYPE(27)
//*-----------------------------------------------------------------------
// @mfunc ppRowset != NULL, Non rowset returning results
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCGetResult_Rowset::Variation_27()
{
BOOL fResults = FALSE;
CMultResults * pMultResults = NULL;
IUnknown * pIRowset = (IUnknown *)0x12345678;
ESQLSTMT rgeSQLStmts[] = {
EINSERT, //Start with non rowset returning
ESELECT,
EINSERT
};
const ULONG ceSQLStmts = sizeof(rgeSQLStmts) / sizeof(ESQLSTMT);
DECL_FLAGSANDIIDS(ceSQLStmts)
//Get an IMultipleResults interface, use our own SQLStmts
if (CHECK(SetUpGetResult(&pMultResults, ceSQLStmts, rgeSQLStmts, rgFlag), S_OK))
if (CHECK(pMultResults->m_pIMultResults->GetResult(NULL,
rgFlag[0],
rgIID[0],
&pMultResults->m_cRowsGetResultAffected,
(IUnknown **)&pIRowset),
S_OK))
if (COMPARE(pIRowset, NULL))
if (COMPARE(pMultResults->IsGetResultRowsAffectedRight(0), TRUE))
if (CHECK(pMultResults->ProcessAllResults(1, IID_IMultipleResults, rgIID), S_OK))
fResults = TRUE;
if((pIRowset)&&(pIRowset!=(IRowset *)0x12345678))
pIRowset->Release();
pIRowset = NULL;
//Cleanup from SetUpGetResult()
if (pMultResults)
{
pMultResults->ReleaseIMultipleResults();
delete pMultResults;
}
if (fResults)
return TEST_PASS;
else
return TEST_FAIL;
}
// }}
// {{ TCW_VAR_PROTOTYPE(28)
//*-----------------------------------------------------------------------
// @mfunc pcRowsAffected == NULL, rowset returning result
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCGetResult_Rowset::Variation_28()
{
IUnknown * pIRowset = NULL;
BOOL fResults = FALSE;
CMultResults * pMultResults = NULL;
ESQLSTMT rgeSQLStmts[] = {
ESELECT, //Start with rowset returning
EINSERT,
ESELECT
};
const ULONG ceSQLStmts = sizeof(rgeSQLStmts) / sizeof(ESQLSTMT);
DECL_FLAGSANDIIDS(ceSQLStmts)
//Get an IMultipleResults interface, use our own SQLStmts
if (CHECK(SetUpGetResult(&pMultResults, ceSQLStmts, rgeSQLStmts, rgFlag), S_OK))
if (CHECK(pMultResults->m_pIMultResults->GetResult(NULL,
rgFlag[0],
rgIID[0],
NULL, //Try NULL pcRowsAffected
(IUnknown **)&pIRowset),
S_OK))
//It should still be valid rowset
if (CHECK(pMultResults->VerifySelectRowset(rgIID[0], pIRowset, (ISROWSET)), S_OK))
{
if (pIRowset)
pIRowset->Release();
pIRowset = NULL;
//Make sure the rest of the results are OK (we processed the first one already)
if (CHECK(pMultResults->ProcessAllResults(1, IID_IMultipleResults, rgIID), S_OK))
fResults = TRUE;
}
//Cleanup from SetUpGetResult()
if (pMultResults)
{
pMultResults->ReleaseIMultipleResults();
delete pMultResults;
}
if (pIRowset)
pIRowset->Release();
pIRowset = NULL;
if (fResults)
return TEST_PASS;
else
return TEST_FAIL;
}
// }}
// {{ TCW_VAR_PROTOTYPE(29)
//*-----------------------------------------------------------------------
// @mfunc pcRowsAffected == NULL, Non rowset returning result
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCGetResult_Rowset::Variation_29()
{
IUnknown * pIRowset = (IUnknown *)0x12345678;
BOOL fResults = FALSE;
CMultResults * pMultResults = NULL;
ESQLSTMT rgeSQLStmts[] = {
EINSERT, //Start with non rowset returning
ESELECT,
EINSERT
};
const ULONG ceSQLStmts = sizeof(rgeSQLStmts) / sizeof(ESQLSTMT);
DECL_FLAGSANDIIDS(ceSQLStmts)
//Get an IMultipleResults interface, use our own SQLStmts
if (CHECK(SetUpGetResult(&pMultResults, ceSQLStmts, rgeSQLStmts, rgFlag), S_OK))
if (CHECK(pMultResults->m_pIMultResults->GetResult(NULL,
rgFlag[0],
rgIID[0],
NULL, //Try NULL pcRowsAffected
(IUnknown **)&pIRowset),
S_OK))
{
//It should be just like an error, outparams nulled
if (pIRowset == NULL)
//Make sure the rest of the results are OK (we processed the first one already)
if (CHECK(pMultResults->ProcessAllResults(1, IID_IMultipleResults, rgIID), S_OK))
fResults = TRUE;
if((pIRowset)&&(pIRowset!=(IRowset *)0x12345678))
pIRowset->Release();
pIRowset = NULL;
}
//Cleanup from SetUpGetResult()
if (pMultResults)
{
pMultResults->ReleaseIMultipleResults();
delete pMultResults;
}
if (fResults)
return TEST_PASS;
else
return TEST_FAIL;
}
// }}
// {{ TCW_VAR_PROTOTYPE(30)
//*-----------------------------------------------------------------------
// @mfunc Multiple Executions of same command open at same time
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCGetResult_Rowset::Variation_30()
{
CBatch oBatch(m_pIDBCreateCommand,
m_pICommandText,
m_pSelectTable,
m_pChangeTable);
ESQLSTMT rgeSQLStmts[] = {
ESELECT,
EUPDATE,
ESELECT,
EUPDATE
};
const ULONG ceSQLStmts = sizeof(rgeSQLStmts) / sizeof(ESQLSTMT);
DECL_FLAGSANDIIDS(ceSQLStmts)
IMultipleResults * pIMultResults1 = NULL;
//Initialize batch statement with the proper SQL for this variation
if (!oBatch.FInit(ceSQLStmts, rgeSQLStmts, rgFlag))
return TEST_FAIL;
//Puts interface in m_pIRowset or m_pIRow.
if (CHECK(oBatch.SetAndExecute(rgIID[0]), S_OK))
{
//Puts interface in m_pIMultResults
if (CHECK(oBatch.Execute(IID_IMultipleResults, NULL), S_OK))
{
//Save this interface so we can write over it to create a new one
pIMultResults1 = oBatch.m_pIMultResults;
//Create another IMultipleResults via another execution
if (CHECK(oBatch.Execute(IID_IMultipleResults, NULL), S_OK))
{
CHECK(oBatch.ProcessAllResults(0, IID_IMultipleResults, rgIID), S_OK);
//Now check results of first IMultResults interface
oBatch.m_pIMultResults = pIMultResults1;
CHECK(oBatch.ProcessAllResults(0, IID_IMultipleResults, rgIID), S_OK);
}
//Try to cleanup in case we had a failure and didn't get to cleanup above
oBatch.ReleaseIMultipleResults();
}
//Now check single IRowset
CHECK(oBatch.VerifySelectRowset(rgIID[0], (ISROWSET) ? oBatch.m_pIRowset : (IUnknown*)oBatch.m_pIRow, (ISROWSET)), S_OK);
//And Release it
oBatch.ReleaseIRowset();
}
//Count on our CHECKs to do any necessary error incrementing
return TEST_PASS;
}
// }}
// {{ TCW_VAR_PROTOTYPE(31)
//*-----------------------------------------------------------------------
// @mfunc Select, insert, select - RestartPosition on first and last select
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCGetResult_Rowset::Variation_31()
{
ESQLSTMT rgeSQLStmts[] = {
ESELECT,
EINSERT,
ESELECT
};
const ULONG ceSQLStmts = sizeof(rgeSQLStmts) / sizeof(ESQLSTMT);
DECL_FLAGSANDIIDS(ceSQLStmts)
//CBatch * poBatch = NULL;
IRowset * pIRowset = NULL;
BOOL fResults = TRUE;
CMultResults * pMultResults = NULL;
DBCOUNTITEM cRowsObtained;
HROW rghRows[1];
HROW * prghRows=rghRows;
////////////////////////////////////////////////
//This is a ODBC Provider specific test!
////////////////////////////////////////////////
if (!g_fKagera && !g_fSQLOLEDB)
return TEST_SKIPPED;
//Create a multiple results object
//if (CHECK(SetUpGetResult((CMultResults **)&poBatch, ceSQLStmts, rgeSQLStmts), S_OK))
if (CHECK(SetUpGetResult(&pMultResults, ceSQLStmts, rgeSQLStmts, rgFlag), S_OK))
{
if (CHECK((pMultResults->m_pIMultResults)->GetResult(NULL,
0,
IID_IRowset,
&pMultResults->m_cRowsGetResultAffected,
(IUnknown **)&(pIRowset)), S_OK))
{
//Need to reexecute, which should be impossible
//since we don't want the undesireable side affects
//of reexecuting the whole batch
if(pIRowset)
{
// We have to retrieve data before DB_S_COMMANDREEXECUTED will be returned by
// some providers
if (CHECK(pIRowset->GetNextRows(NULL, 0, 1, &cRowsObtained, &prghRows), S_OK))
{
if (CHECK(pIRowset->ReleaseRows(1, rghRows, NULL, NULL, NULL), S_OK))
{
if (CHECK(m_hr = pIRowset->RestartPosition(0), DB_S_COMMANDREEXECUTED))
fResults = TRUE;
}
}
pIRowset->Release();
pIRowset = NULL;
}
else
fResults = FALSE;
if (CHECK((pMultResults->m_pIMultResults)->GetResult(NULL,
0,
IID_IRowset,
&pMultResults->m_cRowsGetResultAffected,
(IUnknown **)&(pIRowset)), S_OK))
{
COMPARE(pIRowset, NULL);
COMPARE(pMultResults->IsGetResultRowsAffectedRight(1), TRUE);
if(pIRowset)
{
pIRowset->Release();
pIRowset = NULL;
}
}
else
fResults = FALSE;
if (CHECK((pMultResults->m_pIMultResults)->GetResult(NULL,
0,
IID_IRowset,
&pMultResults->m_cRowsGetResultAffected,
(IUnknown **)&(pIRowset)), S_OK))
{
if(pIRowset)
{
// We have to retrieve data before DB_S_COMMANDREEXECUTED will be returned by
// some providers
if (CHECK(pIRowset->GetNextRows(NULL, 0, 1, &cRowsObtained, &prghRows), S_OK))
{
if (CHECK(pIRowset->ReleaseRows(1, rghRows, NULL, NULL, NULL), S_OK))
{
if (CHECK(m_hr = pIRowset->RestartPosition(0), DB_E_CANNOTRESTART))
fResults = TRUE;
}
}
pIRowset->Release();
pIRowset = NULL;
}
}
else
fResults = FALSE;
}
else
fResults = FALSE;
pMultResults->ReleaseIMultipleResults();
delete pMultResults;
}
else
fResults = FALSE;
if (fResults)
return TEST_PASS;
else
return TEST_FAIL;
}
// }}
// {{ TCW_VAR_PROTOTYPE(32)
//*-----------------------------------------------------------------------
// @mfunc DB_S_NORESULT - Call after receiving DB_S_NORESULT once
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCGetResult_Rowset::Variation_32()
{
ESQLSTMT rgeSQLStmts[] = {
ESELECT,
EINSERT,
ESELECT
};
const ULONG ceSQLStmts = sizeof(rgeSQLStmts) / sizeof(ESQLSTMT);
DECL_FLAGSANDIIDS(ceSQLStmts)
CBatch * poBatch = NULL;
i=0;
//Create a multiple results object
if (CHECK(SetUpGetResult((CMultResults **)&poBatch, ceSQLStmts, rgeSQLStmts, rgFlag), S_OK))
{
while ( (m_hr = (poBatch->m_pIMultResults)->GetResult(NULL,
rgFlag[0],
rgIID[0],
&poBatch->m_cRowsGetResultAffected,
(IUnknown **)&(poBatch->m_pIRowset)) )
!= DB_S_NORESULT)
{
poBatch->ReleaseIRowset();
i++;
//Get out of loop if we receive an error
if (m_hr != DB_S_NORESULT && m_hr != S_OK)
break;
}
//Make sure we did end correctly
CHECK(m_hr, DB_S_NORESULT);
//Now make sure we get the same return code again
CHECK((poBatch->m_pIMultResults)->GetResult(NULL,
rgFlag[0],
rgIID[0],
&poBatch->m_cRowsGetResultAffected,
(IUnknown **)&(poBatch->m_pIRowset)), DB_S_NORESULT);
poBatch->ReleaseIRowset();
poBatch->ReleaseIMultipleResults();
delete poBatch;
return TEST_PASS;
}
return TEST_FAIL;
}
// }}
// {{ TCW_VAR_PROTOTYPE(33)
//*-----------------------------------------------------------------------
// @mfunc DBPROP_IRowsetLocate - insert, update, delete
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCGetResult_Rowset::Variation_33()
{
ESQLSTMT rgeSQLStmts[] = {
EINSERT,
EUPDATE,
EDELETE
};
const ULONG ceSQLStmts = sizeof(rgeSQLStmts) / sizeof(ESQLSTMT);
DECL_FLAGSANDIIDS(ceSQLStmts)
CBatch * poBatch = NULL;
BOOL fResults = TRUE; //In case IRowsetLocate isn't supported
////////////////////////////////////////////////////////////////////////////////////////////////
//This is a Provider specific test due to the use of batch SQL supported by SQL Server!
////////////////////////////////////////////////////////////////////////////////////////////////
if (!g_fKagera && !g_fSQLOLEDB)
return TEST_SKIPPED;
//Only continue if we can set this property
if (SUCCEEDED(SetRowsetPropertyOn(DBPROP_IRowsetLocate)))
{
fResults = FALSE;
// Create a multiple results object
// It is provider specific whether Execute can succeed with batch SQL and IRowsetLocate
// property.
if (SUCCEEDED(SetUpGetResult((CMultResults **)&poBatch, ceSQLStmts, rgeSQLStmts, rgFlag)))
{
//Check the insert results
if (CHECK((poBatch->m_pIMultResults)->GetResult(NULL,
0,
IID_IRowsetLocate,
&poBatch->m_cRowsGetResultAffected,
(IUnknown **)&(poBatch->m_pIRowset)), S_OK))
if (COMPARE(poBatch->AreGetResultOutParamsRight(0, poBatch->m_pIRowset, IID_IRowsetLocate, 0), TRUE))
{
poBatch->ReleaseIRowset();
//Check the update results
if (CHECK((poBatch->m_pIMultResults)->GetResult(NULL,
0,
IID_IRowsetLocate,
&poBatch->m_cRowsGetResultAffected,
(IUnknown **)&(poBatch->m_pIRowset)), S_OK))
if (COMPARE(poBatch->AreGetResultOutParamsRight(1, poBatch->m_pIRowset, IID_IRowsetLocate, 0), TRUE))
{
poBatch->ReleaseIRowset();
//Check the delete results
if (CHECK((poBatch->m_pIMultResults)->GetResult(NULL,
0,
IID_IRowsetLocate,
&poBatch->m_cRowsGetResultAffected,
(IUnknown **)&(poBatch->m_pIRowset)), S_OK))
if (COMPARE(poBatch->AreGetResultOutParamsRight(2, poBatch->m_pIRowset, IID_IRowsetLocate, 0), TRUE))
fResults = TRUE;
}
}
//Now free everything
poBatch->ReleaseIRowset();
poBatch->ReleaseIMultipleResults();
if (poBatch)
delete poBatch;
}
else
{
odtLog<<L"It is provider specific whether Execute succeeds for batch SQL and DBPROP_IRowsetLocate"<<ENDL;
odtLog<<L"Execute failure is allowed but should be verified that it's not a provider bug"<<ENDL;
fResults = TRUE;
}
//Go back to a normal command
CHECK(SetRowsetPropertyDefault(DBPROP_IRowsetLocate), S_OK);
}
if (fResults)
return TEST_PASS;
else
return TEST_FAIL;
}
// }}
// {{ TCW_VAR_PROTOTYPE(34)
//*-----------------------------------------------------------------------
// @mfunc DBPROP_IRowsetLocate - insert, select, delete
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCGetResult_Rowset::Variation_34()
{
ESQLSTMT rgeSQLStmts[] = {
EINSERT,
ESELECT,
EDELETE
};
const ULONG ceSQLStmts = sizeof(rgeSQLStmts) / sizeof(ESQLSTMT);
DECL_FLAGSANDIIDS(ceSQLStmts)
CBatch * poBatch = NULL;
IRowsetLocate * pIRowLoc1 = NULL;
BOOL fResults = TRUE;
HRESULT hr = E_FAIL;
////////////////////////////////////////////////////////////////////////////////////////////////
//This is a Provider specific test due to the use of batch SQL supported by SQL Server!
////////////////////////////////////////////////////////////////////////////////////////////////
if (!g_fKagera && !g_fSQLOLEDB)
return TEST_SKIPPED;
//Only continue if we can set this property
if (SUCCEEDED(SetRowsetPropertyOn(DBPROP_IRowsetLocate)))
{
fResults = FALSE;
//Create a multiple results object. Assuming
//that the only cursor type that can be returned here is forward only, read only,
//we should expect DB_E_ERRORSOCCURRED from ODBC Provider, but not until GetResult
//is called, since we expect the insert to succeed.
if (CHECK(SetUpGetResult((CMultResults **)&poBatch, ceSQLStmts, rgeSQLStmts, rgFlag), S_OK))
{
//Check the insert results
if (CHECK((poBatch->m_pIMultResults)->GetResult(NULL,
0,
IID_IRowsetLocate,
&poBatch->m_cRowsGetResultAffected,
(IUnknown **)&(poBatch->m_pIRowset)), S_OK))
if (COMPARE(poBatch->AreGetResultOutParamsRight(0, poBatch->m_pIRowset, IID_IRowsetLocate, 0), TRUE))
// Check the select. Since the required interface is not available
// this should return E_NOINTERFACE.
hr = (poBatch->m_pIMultResults)->GetResult(NULL,
0,
IID_IRowsetLocate,
&poBatch->m_cRowsGetResultAffected,
(IUnknown **)&pIRowLoc1);
if (hr == S_OK)
{
if (CHECK(TryLocate(pIRowLoc1), S_OK))
//Check the delete
if (CHECK((poBatch->m_pIMultResults)->GetResult(NULL,
0,
IID_IRowsetLocate,
&poBatch->m_cRowsGetResultAffected,
(IUnknown **)&(poBatch->m_pIRowset)), S_OK))
if (COMPARE(poBatch->AreGetResultOutParamsRight(2,
poBatch->m_pIRowset, IID_IRowsetLocate, 0),
TRUE))
fResults = TRUE;
}
else
{
// I'd really like E_NOINTERFACE, but if they detect they can't
// support the required prop we might get DB_E_ERRORSOCCURRED
if (hr != DB_E_ERRORSOCCURRED)
fResults = CHECK(hr, E_NOINTERFACE);
else
fResults = TRUE;
}
}
//Now free everything
if (poBatch)
{
poBatch->ReleaseIRowset();
SAFE_RELEASE(pIRowLoc1);
poBatch->ReleaseIMultipleResults();
delete poBatch;
}
else
{
odtLog<<L"It is provider specific whether Execute succeeds for batch SQL and DBPROP_IRowsetLocate"<<ENDL;
odtLog<<L"Execute failure is allowed but should be verified that it's not a provider bug"<<ENDL;
fResults = TRUE;
}
//Go back to a normal command
CHECK(SetRowsetPropertyDefault(DBPROP_IRowsetLocate), S_OK);
}
if (fResults)
return TEST_PASS;
else
return TEST_FAIL;
}
// }}
// {{ TCW_VAR_PROTOTYPE(35)
//*-----------------------------------------------------------------------
// @mfunc DBPROP_IRowsetLocate - insert, select, select
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCGetResult_Rowset::Variation_35()
{
ESQLSTMT rgeSQLStmts[] = {
EINSERT,
ESELECT,
ESELECT
};
const ULONG ceSQLStmts = sizeof(rgeSQLStmts) / sizeof(ESQLSTMT);
DECL_FLAGSANDIIDS(ceSQLStmts)
CBatch * poBatch = NULL;
BOOL fResults = TRUE; //In case IRowsetLocate isn't supported
HRESULT hr = E_FAIL;
IRowsetLocate * pIRowLoc1 = NULL;
////////////////////////////////////////////////////////////////////////////////////////////////
//This is a Provider specific test due to the use of batch SQL supported by SQL Server!
////////////////////////////////////////////////////////////////////////////////////////////////
if (!g_fKagera && !g_fSQLOLEDB)
return TEST_SKIPPED;
//Only continue if we can set this property
if (SUCCEEDED(SetRowsetPropertyOn(DBPROP_IRowsetLocate)))
{
fResults = FALSE;
//Create a multiple results object. Assuming
//that the only cursor type that can be returned here is forward only, read only,
//we should expect DB_E_ERRORSOCCURRED from ODBC Provider, but not until GetResult
//is called, since we expect the insert to succeed.
if (CHECK(SetUpGetResult((CMultResults **)&poBatch, ceSQLStmts, rgeSQLStmts, rgFlag), S_OK))
{
//Check the insert results
if (CHECK((poBatch->m_pIMultResults)->GetResult(NULL,
0,
IID_IRowsetLocate,
&poBatch->m_cRowsGetResultAffected,
(IUnknown **)&(poBatch->m_pIRowset)), S_OK))
if (COMPARE(poBatch->AreGetResultOutParamsRight(0, poBatch->m_pIRowset, IID_IRowsetLocate, 0), TRUE))
// Check the select. Since the required interface is not available
// this should return E_NOINTERFACE.
hr = (poBatch->m_pIMultResults)->GetResult(NULL,
0,
IID_IRowsetLocate,
&poBatch->m_cRowsGetResultAffected,
(IUnknown **)&pIRowLoc1);
if (hr == S_OK)
{
if (CHECK(TryLocate(pIRowLoc1), S_OK))
//Check the delete
if (CHECK((poBatch->m_pIMultResults)->GetResult(NULL,
0,
IID_IRowsetLocate,
&poBatch->m_cRowsGetResultAffected,
(IUnknown **)&(poBatch->m_pIRowset)), S_OK))
if (COMPARE(poBatch->AreGetResultOutParamsRight(2,
poBatch->m_pIRowset, IID_IRowsetLocate, 0),
TRUE))
fResults = TRUE;
}
else
{
// I'd really like E_NOINTERFACE, but if they detect they can't
// support the required prop we might get DB_E_ERRORSOCCURRED
if (hr != DB_E_ERRORSOCCURRED)
fResults = CHECK(hr, E_NOINTERFACE);
else
fResults = TRUE;
}
}
//Now free everything
if (poBatch)
{
SAFE_RELEASE(pIRowLoc1);
poBatch->ReleaseIRowset();
poBatch->ReleaseIMultipleResults();
delete poBatch;
}
//Go back to a normal command
CHECK(SetRowsetPropertyDefault(DBPROP_IRowsetLocate), S_OK);
}
if (fResults)
return TEST_PASS;
else
return TEST_FAIL;
}
// }}
// {{ TCW_VAR_PROTOTYPE(36)
//*-----------------------------------------------------------------------
// @mfunc DBPROP_CANHOLDROWS
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCGetResult_Rowset::Variation_36()
{
ESQLSTMT rgeSQLStmts[] = {
ESELECT,
EDELETE,
ESELECT
};
const ULONG ceSQLStmts = sizeof(rgeSQLStmts) / sizeof(ESQLSTMT);
DECL_FLAGSANDIIDS(ceSQLStmts)
CBatch * poBatch = NULL;
BOOL fResults = TRUE; //In case IRowsetLocate isn't supported
HRESULT hr = E_FAIL;
////////////////////////////////////////////////
//This is a ODBC Provider specific test!
////////////////////////////////////////////////
if (!g_fKagera)
{
odtLog << L"This is an ODBC Provider specific test.\n";
return TEST_SKIPPED;
}
//Only continue if we can set this property
if (SUCCEEDED(SetRowsetPropertyOn(DBPROP_CANHOLDROWS)))
{
fResults = FALSE;
//Create a multiple results object. Expect that with two selects
//in the batch we can't support CANHOLDROWS
hr = SetUpGetResult((CMultResults **)&poBatch, ceSQLStmts, rgeSQLStmts, rgFlag);
// Some providers will return DB_E_ERRORSINCOMMAND because they can't distinguish
// a property failure.
if (hr == DB_E_ERRORSINCOMMAND || CHECK(hr, DB_E_ERRORSOCCURRED))
{
fResults = TRUE;
}
if (poBatch)
{
poBatch->ReleaseIRowset();
poBatch->ReleaseIMultipleResults();
delete poBatch;
}
//Go back to a normal command
CHECK(SetRowsetPropertyDefault(DBPROP_CANHOLDROWS), S_OK);
}
if (fResults)
return TEST_PASS;
else
return TEST_FAIL;
}
// }}
// {{ TCW_VAR_PROTOTYPE(37)
//*-----------------------------------------------------------------------
// @mfunc E_NOINTERFACE - IID_IMultipleResults on IOpenRowset::OpenRowset
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCGetResult_Rowset::Variation_37()
{
ESQLSTMT rgeSQLStmts[] = {ESELECT};
const ULONG ceSQLStmts = sizeof(rgeSQLStmts) / sizeof(ESQLSTMT);
DECL_FLAGSANDIIDS(ceSQLStmts)
CBatch oSingle(m_pIDBCreateCommand,
m_pICommandText,
m_pSelectTable,
m_pChangeTable);
IOpenRowset * pIOpenRowset = NULL;
IMultipleResults * pIMultRes = NULL;
IRowset * pIRowset = NULL;
BOOL fResults = FALSE;
DBID TableID;
HRESULT hr = E_FAIL;
TableID = m_pSelectTable->GetTableID();
if (VerifyInterface(m_pThisTestModule->m_pIUnknown2, IID_IOpenRowset,
SESSION_INTERFACE, (IUnknown **)&pIOpenRowset))
{
hr = pIOpenRowset->OpenRowset(NULL,
&TableID,
NULL,
IID_IMultipleResults, //Shouldn't work
0,
NULL,
(IUnknown **)&pIMultRes);
if (hr == E_NOINTERFACE)
fResults = COMPARE(pIMultRes, NULL);
else if (hr == S_OK)
{
// Set up batch for ease in verification.
// Note: We assume OpenRowset is equivalent to "select *"
TESTC(pIMultRes != NULL);
//Initialize batch statement with the proper SQL for this variation
if (!oSingle.FInit(ceSQLStmts, rgeSQLStmts, rgFlag))
goto CLEANUP;
//Set the imultres interface
oSingle.m_pIMultResults = pIMultRes;
pIMultRes->AddRef(); // Because it gets released by ProcessAllResults.
//Test that all results are correct
fResults = CHECK(oSingle.ProcessAllResults(0, IID_IMultipleResults, rgIID), S_OK);
}
else
fResults = CHECK(hr, E_NOINTERFACE);
}
else
{
odtLog << L"FAILURE: IOpenRowset (mandatory interafce) is not supported.\n";
return TEST_FAIL;
}
CLEANUP:
SAFE_RELEASE(pIMultRes);
SAFE_RELEASE(pIRowset);
SAFE_RELEASE(pIOpenRowset);
return fResults ? TEST_PASS : TEST_FAIL;
}
// }}
// {{ TCW_VAR_PROTOTYPE(38)
//*-----------------------------------------------------------------------
// @mfunc E_NOINTERFACE - IID_IMultipleResults on IDBSchemaRowset::GetRowset
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCGetResult_Rowset::Variation_38()
{
IDBSchemaRowset * pIDBSchemaRowset = NULL;
BOOL fResults = FALSE;
IRowset * pIRowset = (IRowset *)0x12345678;
//This interface is optional, so pass if we don't support it
if (!VerifyInterface(m_pThisTestModule->m_pIUnknown2, IID_IDBSchemaRowset,
SESSION_INTERFACE, (IUnknown **)&pIDBSchemaRowset))
return TEST_SKIPPED;
fResults = CHECK(pIDBSchemaRowset->GetRowset(NULL,
DBSCHEMA_TABLES,
0,
NULL,
IID_IMultipleResults, //Shouldn't work
0,
NULL,
(IUnknown **)&pIRowset),
E_NOINTERFACE);
COMPARE (pIRowset, NULL);
pIDBSchemaRowset->Release();
pIDBSchemaRowset = NULL;
if(pIRowset && (pIRowset != (IRowset *)0x12345678))
pIRowset->Release();
pIRowset = NULL;
if (fResults)
return TEST_PASS;
else
return TEST_FAIL;
}
// }}
// {{ TCW_VAR_PROTOTYPE(39)
//*-----------------------------------------------------------------------
// @mfunc Select with empty rowset, mixed with poulated rowsets
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCGetResult_Rowset::Variation_39()
{
CBatch oBatch(m_pIDBCreateCommand,
m_pICommandText,
m_pSelectTable,
m_pChangeTable);
ESQLSTMT rgeSQLStmts[] = {
ESELECT,
EEMPTYSELECT,
EINSERT,
ESELECT
};
const ULONG ceSQLStmts = sizeof(rgeSQLStmts) / sizeof(ESQLSTMT);
DECL_FLAGSANDIIDS(ceSQLStmts)
//Initialize batch statement with the proper SQL for this variation
if (!oBatch.FInit(ceSQLStmts, rgeSQLStmts, rgFlag))
return TEST_FAIL;
//Test that all results are correct
return TestValidMultResults(oBatch, rgIID);
}
// }}
// {{ TCW_VAR_PROTOTYPE(40)
//*-----------------------------------------------------------------------
// @mfunc Release IMultipleResults while Rowset open
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCGetResult_Rowset::Variation_40()
{
//IRowset * pIRowset = (IRowset *)0x12345678; //Init so we know if it's nulled
IRowset * pIRowset = NULL;
BOOL fResults = FALSE;
CMultResults * pMultResults = NULL;
ESQLSTMT rgeSQLStmts[] = {
ESELECT,
EINSERT,
};
const ULONG ceSQLStmts = sizeof(rgeSQLStmts) / sizeof(ESQLSTMT);
DECL_FLAGSANDIIDS(ceSQLStmts)
//Get an IMultipleResults interface
if (CHECK(SetUpGetResult(&pMultResults,
ceSQLStmts,
rgeSQLStmts, rgFlag),
S_OK))
//Do a successful call
if (CHECK(pMultResults->m_pIMultResults->GetResult(NULL,
rgFlag[0],
rgIID[0],
&pMultResults->m_cRowsGetResultAffected,
(IUnknown **)&pIRowset),
S_OK))
{
//Now should be able to release IMultipleResults
pMultResults->ReleaseIMultipleResults();
//Should also still be able to use our rowset
if (CHECK(pMultResults->VerifySelectRowset(rgIID[0], pIRowset, (ISROWSET)), S_OK))
fResults = TRUE;
pIRowset->Release();
pIRowset = NULL;
}
//Cleanup from SetUpGetResult()
if (pMultResults)
{
pMultResults->ReleaseIMultipleResults();
delete pMultResults;
}
if (fResults)
return TEST_PASS;
else
return TEST_FAIL;
}
// }}
// {{ TCW_VAR_PROTOTYPE(41)
//*-----------------------------------------------------------------------
// @mfunc Rowset creation failure do to E_NOINTERFACE
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCGetResult_Rowset::Variation_41()
{
IRowset * pIRowset = (IRowset *)0x12345678; //Init so we know if it's nulled
BOOL fResults = FALSE;
CMultResults * pMultResults = NULL;
ESQLSTMT rgeSQLStmts[] = {
ESELECT,
EINSERT,
ESELECT
};
const ULONG ceSQLStmts = sizeof(rgeSQLStmts) / sizeof(ESQLSTMT);
DECL_FLAGSANDIIDS(ceSQLStmts)
//Get an IMultipleResults interface
if (CHECK(SetUpGetResult(&pMultResults,
ceSQLStmts,
rgeSQLStmts, rgFlag),
S_OK))
//Do a call getting E_NOINTERFACE
if (CHECK(pMultResults->m_pIMultResults->GetResult(NULL,
rgFlag[0],
IID_IRowsetUpdate,
&pMultResults->m_cRowsGetResultAffected,
(IUnknown **)&pIRowset),
E_NOINTERFACE))
{
//Now try again with a valid interface
//TODO: Uncomment if the provider allows
/*if (CHECK(pMultResults->m_pIMultResults->GetResult(NULL,
0,
IID_IRowset,
&pMultResults->m_cRowsGetResultAffected,
(IUnknown **)&pIRowset),
S_OK))
if (CHECK(pMultResults->VerifySelectRowset(IID_IRowset, pIRowset), S_OK))
{
pIRowset->Release();
pIRowset = NULL;
//Should also still be able to process the rest of the results
if (CHECK(pMultResults->ProcessAllResults(1), S_OK))
fResults = TRUE;
}*/
COMPARE (pIRowset, NULL);
if (CHECK(pMultResults->ProcessAllResults(1, IID_IMultipleResults, rgIID), S_OK))
fResults = TRUE;
if ((pIRowset)&&(pIRowset!=(IRowset *)0x12345678))
pIRowset->Release();
pIRowset = NULL;
}
//Cleanup from SetUpGetResult()
if (pMultResults)
{
pMultResults->ReleaseIMultipleResults();
delete pMultResults;
}
if (fResults)
return TEST_PASS;
else
return TEST_FAIL;
}
// }}
// {{ TCW_VAR_PROTOTYPE(42)
//*-----------------------------------------------------------------------
// @mfunc Rowset creation failure due to non forward only cursor
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCGetResult_Rowset::Variation_42()
{
IUnknown * pIRowset = (IUnknown *)0x12345678; //Init so we know if it's nulled
IRowsetLocate * pIRowsetLocate = (IRowsetLocate *)0x12345678; //Init so we know if it's nulled
BOOL fResults = FALSE;
CMultResults * pMultResults = NULL;
ESQLSTMT rgeSQLStmts[] = {
ESELECT,
ESELECT,
ESELECT
};
const ULONG ceSQLStmts = sizeof(rgeSQLStmts) / sizeof(ESQLSTMT);
DECL_FLAGSANDIIDS(ceSQLStmts)
////////////////////////////////////////////////
//This is a ODBC Provider specific test!
////////////////////////////////////////////////
if (!g_fKagera)
return TEST_SKIPPED;
//Get an IMultipleResults interface
if (CHECK(SetUpGetResult(&pMultResults,
ceSQLStmts,
rgeSQLStmts, rgFlag),
S_OK))
//Do a call getting regular supported rowset
if (CHECK(pMultResults->m_pIMultResults->GetResult(NULL,
rgFlag[0],
rgIID[0],
&pMultResults->m_cRowsGetResultAffected,
(IUnknown **)&pIRowset),
S_OK))
{
if (CHECK(pMultResults->VerifySelectRowset(rgIID[0], pIRowset, (ISROWSET)), S_OK))
{
pIRowset->Release();
pIRowset = NULL;
//Now try again with a non forward only rowset
//TODO:
if (CHECK(m_hr = pMultResults->m_pIMultResults->GetResult(NULL,
rgFlag[1],
IID_IRowsetLocate,
&pMultResults->m_cRowsGetResultAffected,
(IUnknown **)&pIRowsetLocate),
E_NOINTERFACE))
{
COMPARE (pIRowsetLocate, NULL);
if (pIRowsetLocate && (pIRowsetLocate!= (IRowsetLocate *)0x12345678))
pIRowsetLocate->Release();
pIRowsetLocate = NULL;
//Get same result again, this time with valid interface
if (CHECK(pMultResults->m_pIMultResults->GetResult(NULL,
rgFlag[2],
rgIID[2],
&pMultResults->m_cRowsGetResultAffected,
(IUnknown **)&pIRowset),
S_OK))
{
if (CHECK(pMultResults->VerifySelectRowset(rgIID[2], pIRowset, (ISROWSET)), S_OK))
{
pIRowset->Release();
pIRowset = NULL;
//Should also still be able to process the rest of the results
//TODO: May need to change this from 3 to 2 depending on the provider
if (CHECK(pMultResults->ProcessAllResults(3, IID_IMultipleResults, rgIID), S_OK))
fResults = TRUE;
}
}
}
}
}
//Cleanup from SetUpGetResult()
if (pMultResults)
{
pMultResults->ReleaseIMultipleResults();
delete pMultResults;
}
if (fResults)
return TEST_PASS;
else
return TEST_FAIL;
}
// }}
// {{ TCW_VAR_PROTOTYPE(43)
//*-----------------------------------------------------------------------
// @mfunc Multiple ParamSets in a batch - select, insert, select
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCGetResult_Rowset::Variation_43()
{
CParamSets oParamSets(3, //Use three param sets
m_pIDBCreateCommand,
m_pICommandText,
m_pSelectTable,
m_pChangeTable);
ESQLSTMT rgeSQLStmts[] = {
ESELECT,
EINSERT,
ESELECT
};
const ULONG ceSQLStmts = sizeof(rgeSQLStmts) / sizeof(ESQLSTMT);
if (!g_bMultipleParamSets)
{
odtLog << "Multiple parameter sets are not supported \n";
return TEST_SKIPPED;
}
DECL_FLAGSANDIIDS(6)
//Initialize batch statement with the proper SQL for this variation
if (!oParamSets.FInit(ceSQLStmts, rgeSQLStmts, rgFlag, NUMELEM(rgFlag)))
return TEST_FAIL;
//Test that all results are correct
return TestValidMultResults(oParamSets, rgIID);
}
// }}
// {{ TCW_VAR_PROTOTYPE(44)
//*-----------------------------------------------------------------------
// @mfunc Multiple ParamSets in a batch - insert, select, insert
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCGetResult_Rowset::Variation_44()
{
CParamSets oParamSets(2,
m_pIDBCreateCommand,
m_pICommandText,
m_pSelectTable,
m_pChangeTable);
ESQLSTMT rgeSQLStmts[] = {
EINSERT,
ESELECT,
EINSERT
};
const ULONG ceSQLStmts = sizeof(rgeSQLStmts) / sizeof(ESQLSTMT);
if (!g_bMultipleParamSets)
{
odtLog << "Multiple parameter sets are not supported \n";
return TEST_SKIPPED;
}
DECL_FLAGSANDIIDS(3)
//Initialize batch statement with the proper SQL for this variation
if (!oParamSets.FInit(ceSQLStmts, rgeSQLStmts, rgFlag, NUMELEM(rgFlag)))
return TEST_FAIL;
// Test that all results are correct
// Note the spec states it's an error to use multiple paramsets with row
// returning statements
return TestValidMultResults(oParamSets, rgIID);
}
// }}
// {{ TCW_VAR_PROTOTYPE(45)
//*-----------------------------------------------------------------------
// @mfunc Multiple ParamSets in a batch - select, select, select
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCGetResult_Rowset::Variation_45()
{
CParamSets oParamSets(3, //Use three param sets
m_pIDBCreateCommand,
m_pICommandText,
m_pSelectTable,
m_pChangeTable);
ESQLSTMT rgeSQLStmts[] = {
ESELECT,
ESELECT,
ESELECT
};
const ULONG ceSQLStmts = sizeof(rgeSQLStmts) / sizeof(ESQLSTMT);
if (!g_bMultipleParamSets)
{
odtLog << "Multiple parameter sets are not supported \n";
return TEST_SKIPPED;
}
DECL_FLAGSANDIIDS(9)
//Initialize batch statement with the proper SQL for this variation
if (!oParamSets.FInit(ceSQLStmts, rgeSQLStmts, rgFlag, NUMELEM(rgFlag)))
return TEST_FAIL;
//Test that all results are correct
return TestValidMultResults(oParamSets, rgIID);
}
// }}
// {{ TCW_VAR_PROTOTYPE(46)
//--------------------------------------------------------------------
// @mfunc single select, RestartPosition -- DB_S_COMMANDREEXECUTED
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCGetResult_Rowset::Variation_46()
{
CBatch oSingle(m_pIDBCreateCommand,
m_pICommandText,
m_pSelectTable,
m_pChangeTable);
ESQLSTMT rgeSQLStmts[] = {
ESELECT,
};
const ULONG ceSQLStmts = sizeof(rgeSQLStmts) / sizeof(ESQLSTMT);
IRowset *pIRowset = NULL;
BOOL fResults = FALSE;
DBCOUNTITEM cRowsObtained;
HROW rghRows[1];
HROW * prghRows=rghRows;
DECL_FLAGSANDIIDS(ceSQLStmts)
//Initialize batch statement with the proper SQL for this variation
if (!oSingle.FInit(ceSQLStmts, rgeSQLStmts, rgFlag))
return TEST_FAIL;
if (CHECK(oSingle.SetAndExecute(IID_IMultipleResults), S_OK))
{
//if (CHECK((poBatch->m_pIMultResults)->GetResult(NULL,
if (CHECK((oSingle.m_pIMultResults)->GetResult(NULL,
0,
IID_IRowset,
&oSingle.m_cRowsGetResultAffected,
(IUnknown **)&(pIRowset)), S_OK))
{
if(pIRowset)
{
// We have to retrieve data before DB_S_COMMANDREEXECUTED will be returned by
// some providers
if (CHECK(pIRowset->GetNextRows(NULL, 0, 1, &cRowsObtained, &prghRows), S_OK))
{
if (CHECK(pIRowset->ReleaseRows(1, rghRows, NULL, NULL, NULL), S_OK))
{
m_hr = pIRowset->RestartPosition(0);
if (m_hr == S_OK || CHECK(m_hr, DB_S_COMMANDREEXECUTED))
fResults = TRUE;
}
}
pIRowset->Release();
pIRowset = NULL;
}
}
}
oSingle.ReleaseIMultipleResults();
if (fResults)
return TEST_PASS;
else
return TEST_FAIL;
}
// }}
// {{ TCW_VAR_PROTOTYPE(47)
//*-----------------------------------------------------------------------
// @mfunc S_OK - Select on 2nd command while processing GetResult on first command
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCGetResult_Rowset::Variation_47()
{
IUnknown * pIRowset = (IUnknown *)0x12345678; //Init so we know if it's nulled
ICommand * pICommand = NULL;
BOOL fResults = FALSE;
CMultResults * pMultResults = NULL;
ESQLSTMT rgeSQLStmts[] = {
ESELECT,
ESELECT,
ESELECT
};
const ULONG ceSQLStmts = sizeof(rgeSQLStmts) / sizeof(ESQLSTMT);
DECL_FLAGSANDIIDS(ceSQLStmts)
//Get an IMultipleResults interface
if (CHECK(SetUpGetResult(&pMultResults, ceSQLStmts, rgeSQLStmts, rgFlag), S_OK))
{
//Do a successful call
if (CHECK(pMultResults->m_pIMultResults->GetResult(NULL,
rgFlag[0],
rgIID[0],
&pMultResults->m_cRowsGetResultAffected,
(IUnknown **)&pIRowset),
S_OK))
{
// Check the results
TESTC(pIRowset != NULL);
COMPARE(pMultResults->m_cRowsGetResultAffected, -1);
// Release the rows and rowset
if(pIRowset && (pIRowset != (IUnknown *)0x12345678))
pIRowset->Release();
// Create a second command object and open a rowset on it
TESTC_(m_pSelectTable->ExecuteCommand(SELECT_ORDERBYNUMERIC, IID_IRowset, NULL,
NULL, NULL, NULL, EXECUTE_IFNOERROR, 0, NULL, NULL, (IUnknown**)&pIRowset,
&pICommand), S_OK);
// Validate the data also.
TESTC_(pMultResults->VerifySelectRowset(IID_IRowset, pIRowset, TRUE), S_OK);
SAFE_RELEASE(pIRowset);
pIRowset = (IRowset *)0x12345678;
//Try unsupported IID
if (CHECK(pMultResults->m_pIMultResults->GetResult(NULL,
rgFlag[1],
IID_IMultipleResults,
&pMultResults->m_cRowsGetResultAffected,
(IUnknown **)&pIRowset),
E_NOINTERFACE))
if ((pMultResults->CheckErrorOutParams(pIRowset))&&(COMPARE(pMultResults->m_cRowsGetResultAffected,-1)) )
//the current is lost. Now verify the next one
if (CHECK(pMultResults->m_pIMultResults->GetResult(NULL,
rgFlag[2],
rgIID[2],
&pMultResults->m_cRowsGetResultAffected,
(IUnknown **)&pIRowset),
S_OK))
{
if (CHECK(pMultResults->VerifySelectRowset(rgIID[2], pIRowset, (ISROWSET)), S_OK))
fResults = TRUE;
pIRowset->Release();
pIRowset = NULL;
}
}
}
CLEANUP:
//Cleanup from SetUpGetResult()
if (pMultResults)
{
pMultResults->ReleaseIMultipleResults();
delete pMultResults;
}
SAFE_RELEASE(pICommand);
if (fResults)
return TEST_PASS;
else
return TEST_FAIL;
}
// }} TCW_VAR_PROTOTYPE_END
// {{ TCW_VAR_PROTOTYPE(48)
//*-----------------------------------------------------------------------
// @mfunc S_OK - Single select, ask for IID_IRowsetScroll
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCGetResult_Rowset::Variation_48()
{
CBatch oSingle(m_pIDBCreateCommand,
m_pICommandText,
m_pSelectTable,
m_pChangeTable);
ESQLSTMT rgeSQLStmts[] = {
ESELECT,
};
const ULONG ceSQLStmts = sizeof(rgeSQLStmts) / sizeof(ESQLSTMT);
DECL_FLAGSANDIIDS(ceSQLStmts)
//Change all IIDs to IID_IRowsetScroll for the TC_Rowset case,
//and expect to get a ROWSET.
//For the TC_Row case, use DEFAULT flag with IID_IRow, and
//the fact that we set DBPROP_IRowsetScroll (TRUE) should not
//affect getting back a ROW.
for(i=0; i<ceSQLStmts; i++)
{
if(ISROWSET)
rgIID[i] = IID_IRowsetScroll;
else
{
rgFlag[i] = DBRESULTFLAG_DEFAULT;
rgIID[i] = IID_IRow;
}
}
// Since we're only asking Execute for IID_IMultipleResults we need to
// require IID_IRowsetScroll on the rowset or GetResult may not necessarily
// be able to return it.
if (FAILED(SetRowsetPropertyOn(DBPROP_IRowsetScroll)))
{
odtLog << L"Couldn't set DBPROP_IRowsetScroll on.\n";
return TEST_SKIPPED;
}
//Initialize batch statement with the proper SQL for this variation
if (!oSingle.FInit(ceSQLStmts, rgeSQLStmts, rgFlag))
return TEST_FAIL;
//Test that all results are correct
return TestValidMultResults(oSingle, rgIID);
}
// }} TCW_VAR_PROTOTYPE_END
// {{ TCW_VAR_PROTOTYPE(49)
//*-----------------------------------------------------------------------
// @mfunc Aggregated batch - select, select, select
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCGetResult_Rowset::Variation_49()
{
ESQLSTMT rgeSQLStmts[] = {ESELECT, ESELECT, ESELECT};
const ULONG ceSQLStmts = sizeof(rgeSQLStmts) / sizeof(ESQLSTMT);
CBatch * pBatch = NULL;
ICommandText * pIAggCommandText = NULL;
IUnknown * pIAggUnknown = NULL;
TESTRESULT testresult = TEST_FAIL;
HRESULT hr = E_FAIL;
DECL_FLAGSANDIIDS(ceSQLStmts)
CAggregate Aggregate;
// Hack for Sql Server: If we have a valid command object we must release it
// before creating a new one otherwise we end up with a server cursor which
// doesn't support IMultipleResults
SAFE_RELEASE(m_pICommandText);
// Create a new ICommandText object aggregated from IDBCreateCommand object.
hr = m_pIDBCreateCommand->CreateCommand(&Aggregate, IID_IUnknown,
(IUnknown **)&pIAggUnknown);
Aggregate.SetUnkInner(pIAggUnknown);
TESTC(Aggregate.VerifyAggregationQI(hr, IID_ICommand));
if (DB_E_NOAGGREGATION == hr || CLASS_E_NOAGGREGATION == hr)
{
testresult = TEST_SKIPPED;
goto CLEANUP;
}
// See if we can get ICommandText off our aggregated object
TESTC_(Aggregate.QueryInterface(IID_ICommandText, (void **)&pIAggCommandText), S_OK);
pBatch = new CBatch(m_pIDBCreateCommand, pIAggCommandText, m_pSelectTable, m_pChangeTable);
if (!pBatch)
{
odtLog << L"Out of memory!\n";
goto CLEANUP;
}
//Initialize batch statement with the proper SQL for this variation
TESTC(pBatch->FInit(ceSQLStmts, rgeSQLStmts, rgFlag));
//Test that all results are correct
TESTC(TestValidMultResults(*(CMultResults *)pBatch, rgIID));
SAFE_DELETE(pBatch);
// Now release our aggregated command text object and IUnknown
// We expect the aggregated object to go away when the last ref is released.
SAFE_RELEASE(pIAggCommandText);
TESTC(Aggregate.GetRefCount()==1); // Object gone!
testresult = TEST_PASS;
CLEANUP:
SAFE_DELETE(pBatch);
SAFE_RELEASE(pIAggUnknown);
SAFE_RELEASE(pIAggCommandText);
// Now we must restore the member command text object
if (!CHECK(m_pIDBCreateCommand->CreateCommand(NULL, IID_ICommandText, (IUnknown **)&m_pICommandText), S_OK))
{
odtLog << L"Fatal error, unable to recreate command text object.\n.";
testresult = TEST_FAIL;
}
return testresult;
}
// }} TCW_VAR_PROTOTYPE_END
// {{ TCW_VAR_PROTOTYPE(50)
//*-----------------------------------------------------------------------
// @mfunc Aggregated Result - Select, Select, Select
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCGetResult_Rowset::Variation_50()
{
HRESULT hrExecute = E_FAIL;
HRESULT hrSetProp = E_FAIL;
ULONG iProp;
ULONG cInterfaces;
INTERFACEMAP * prgInterfaces = NULL;
ESQLSTMT rgeSQLStmts[] = {ESELECT, ESELECT, ESELECT};
const ULONG ceSQLStmts = sizeof(rgeSQLStmts) / sizeof(ESQLSTMT);
DECL_FLAGSANDIIDS(ceSQLStmts)
CMultResults * pMultResults = NULL;
IUnknown * pIRowset = NULL;
TESTRESULT testresult = TEST_PASS;
HRESULT hr = E_FAIL;
CAggregate * pAggregate = NULL;
IUnknown * pIAggUnknown = NULL;
i=0;
// Get the list of rowset interfaces/properties
TESTC(GetInterfaceArray(ROWSET_INTERFACE, &cInterfaces, &prgInterfaces));
for (iProp=0; iProp < cInterfaces; iProp++)
{
odtLog << prgInterfaces[iProp].pwszName << L"\n";
if (!SettableProperty(prgInterfaces[iProp].dwPropertyID, DBPROPSET_ROWSET,
m_pThisTestModule->m_pIUnknown, ROWSET_INTERFACE))
continue;
hrSetProp = SetRowsetProperty(m_pICommandText, DBPROPSET_ROWSET, prgInterfaces[iProp].dwPropertyID, TRUE);
// This property may conflict with default property settings, so allow DB_E_ERRORSOCCURRED
if (hrSetProp == DB_E_ERRORSOCCURRED)
continue;
CHECK(hrSetProp, S_OK);
hrExecute = SetUpGetResult(&pMultResults, ceSQLStmts, rgeSQLStmts, rgFlag);
// This should always be S_OK or DB_E_ERRORSOCCURRED, but due to provider bug may
// return DB_S_ERRORSOCCURRED.
if (SUCCEEDED(hrExecute))
{
CHECK(hrExecute, S_OK);
for (i=0; i<ceSQLStmts+1; i++)
{
pAggregate = new CAggregate;
TESTC(pAggregate != NULL);
hr = pMultResults->m_pIMultResults->GetResult(pAggregate,
rgFlag[0],
IID_IUnknown,
&pMultResults->m_cRowsGetResultAffected,
(IUnknown **)&pIAggUnknown);
pAggregate->SetUnkInner(pIAggUnknown);
// Make sure there are no more results
if (i == ceSQLStmts)
{
TESTC_(hr, DB_S_NORESULT);
TESTC(pMultResults->m_cRowsGetResultAffected == -1);
TESTC(pIAggUnknown == NULL);
}
else
{
// This is a valid result, process it.
if (!pAggregate->VerifyAggregationQI(hr, rgIID[0]))
{
// We depend on LTM turning this into TEST_FAILURE if there is one
testresult=TEST_SKIPPED;
goto CLEANUP;
}
TESTC(VerifyInterface(pAggregate, rgIID[0],
(ISROWSET) ? ROWSET_INTERFACE : ROW_INTERFACE,
(IUnknown **)&pIRowset));
//Check everything is correct for this result
if (!COMPARE(pMultResults->AreGetResultOutParamsRight(i, pIRowset, rgIID[0], rgFlag[0]), TRUE))
odtLog << L"GetResult output params are not right for result: " << i+1 << wszNewLine;
SAFE_RELEASE(pIRowset);
TESTC(pAggregate->GetRefCount()==1); // Object gone!
SAFE_RELEASE(pIAggUnknown);
SAFE_DELETE(pAggregate);
}
}
SAFE_RELEASE(pMultResults->m_pIMultResults);
SAFE_DELETE(pMultResults);
}
else if (hrExecute == DB_E_ERRORSOCCURRED)
{
COMPARE(IsServerCursorProperty(prgInterfaces[iProp].dwPropertyID), TRUE);
}
else
CHECK(hrExecute, S_OK);
// Set property back to default to avoid any other interactions.
CHECK(SetRowsetPropertyDefault(prgInterfaces[iProp].dwPropertyID), S_OK);
}
testresult = TEST_PASS;
CLEANUP:
SAFE_RELEASE(pIRowset);
SAFE_RELEASE(pIAggUnknown);
SAFE_DELETE(pAggregate);
if (pMultResults)
SAFE_RELEASE(pMultResults->m_pIMultResults);
SAFE_DELETE(pMultResults);
return testresult;
}
// }} TCW_VAR_PROTOTYPE_END
// {{ TCW_VAR_PROTOTYPE(51)
//*-----------------------------------------------------------------------
// @mfunc DBPROP_IMultipleResults - Execute with IID_IUnknown but DBPROP_IMultipleResults
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCGetResult_Rowset::Variation_51()
{
HRESULT hrExecute = E_FAIL;
HRESULT hrSetProp = E_FAIL;
ULONG iProp;
ULONG cInterfaces;
INTERFACEMAP * prgInterfaces = NULL;
CBatch oBatch(m_pIDBCreateCommand,
m_pICommandText,
m_pSelectTable,
m_pChangeTable);
ESQLSTMT rgeSQLStmts[] = {
ESELECT,
EUPDATE,
ESELECT,
EUPDATE
};
const ULONG ceSQLStmts = sizeof(rgeSQLStmts) / sizeof(ESQLSTMT);
DECL_FLAGSANDIIDS(ceSQLStmts)
TESTC(GetInterfaceArray(ROWSET_INTERFACE, &cInterfaces, &prgInterfaces));
// Set on DBPROP_IMultipleResults
CHECK(SetRowsetProperty(m_pICommandText, DBPROPSET_ROWSET, DBPROP_IMultipleResults, TRUE), S_OK);
for (iProp=0; iProp < cInterfaces; iProp++)
{
odtLog << prgInterfaces[iProp].pwszName << L"\n";
if (!SettableProperty(prgInterfaces[iProp].dwPropertyID, DBPROPSET_ROWSET,
m_pThisTestModule->m_pIUnknown, ROWSET_INTERFACE))
continue;
hrSetProp = SetRowsetProperty(m_pICommandText, DBPROPSET_ROWSET, prgInterfaces[iProp].dwPropertyID, TRUE);
// This property may conflict with default property settings, so allow DB_E_ERRORSOCCURRED
if (hrSetProp == DB_E_ERRORSOCCURRED)
continue;
CHECK(hrSetProp, S_OK);
//Initialize batch statement with the proper SQL for this variation
if (!oBatch.FInit(ceSQLStmts, rgeSQLStmts, rgFlag))
return TEST_FAIL;
//Puts interface in m_pIMultRes
// Note: For SQL Server, at least, we must have a FO/RO cursor to be able to support
// IMultipleResults object, so asking for a prop that would require a server cursor
// will return DB_E_ERRORSOCCURRED, which is legal.
hrExecute = oBatch.SetAndExecute(IID_IUnknown);
if (hrExecute == S_OK)
{
CHECK(oBatch.ProcessAllResults(0, IID_IMultipleResults, rgIID), S_OK);
//Try to cleanup in case we had a failure and didn't get to cleanup above
oBatch.ReleaseIMultipleResults();
}
else if (hrExecute == DB_E_ERRORSOCCURRED)
{
COMPARE(IsServerCursorProperty(prgInterfaces[iProp].dwPropertyID), TRUE);
}
else
CHECK(hrExecute, S_OK);
// Set property back to default to avoid any other interactions.
CHECK(SetRowsetPropertyDefault(prgInterfaces[iProp].dwPropertyID), S_OK);
}
// Set property back to default to avoid any other interactions.
CHECK(SetRowsetPropertyDefault(DBPROP_IMultipleResults), S_OK);
//Count on our CHECKs to do any necessary error incrementing
return TEST_PASS;
CLEANUP:
// Make sure our multiple results object is released.
oBatch.ReleaseIMultipleResults();
return TEST_FAIL;
}
// }} TCW_VAR_PROTOTYPE_END
// {{ TCW_VAR_PROTOTYPE(52)
//*-----------------------------------------------------------------------
// @mfunc DB_E_INTEGRITYVIOLATION: Batch - select, insert, select. Fail insert.
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCGetResult_Rowset::Variation_52()
{
ULONG iResult = 0;
BOOL fResult = TEST_FAIL;
CBatch oBatch(m_pIDBCreateCommand,
m_pICommandText,
m_pSelectTable,
m_pSelectTable);
ESQLSTMT rgeSQLStmts[] = {
ESELECT,
EINSERT,
ESELECT
};
const ULONG ceSQLStmts = sizeof(rgeSQLStmts) / sizeof(ESQLSTMT);
DECL_FLAGSANDIIDS(ceSQLStmts)
CCol ColIndex;
DBORDINAL ulIndexCol = 1;
HRESULT hrCreateIndex = E_FAIL;
// If the index column happens to be an autoincrement or non-updatable column
// then the insert query below will not contain that column and the integrity
// violation will not occur. To prevent this create another index.
ulIndexCol = m_pSelectTable->GetIndexColumn();
TESTC_(m_pSelectTable->GetColInfo(ulIndexCol, ColIndex), S_OK);
if (ColIndex.GetAutoInc())
{
ULONG iNewIndex;
for (iNewIndex = 1; iNewIndex <= m_pSelectTable->CountColumnsOnTable();
iNewIndex++)
{
if (iNewIndex == ulIndexCol)
continue;
TESTC_(m_pSelectTable->GetColInfo(iNewIndex, ColIndex), S_OK);
// Providers generally cannot create an index on autoincrement, non-updatable, or bool cols
if (!ColIndex.GetAutoInc() && ColIndex.GetUpdateable() && ColIndex.GetProviderType() != DBTYPE_BOOL)
break;
}
TESTC(iNewIndex <= m_pSelectTable->CountColumnsOnTable());
// Since there's already an index with the default name we need to
// create one with a new name.
TESTC_(m_pSelectTable->GetColInfo(iNewIndex, ColIndex), S_OK);
hrCreateIndex = m_pSelectTable->CreateIndex(iNewIndex, UNIQUE, ColIndex.GetColName());
TESTC_(hrCreateIndex, S_OK);
}
TESTC(oBatch.FInit(ceSQLStmts, rgeSQLStmts, rgFlag));
//Create a multiple results object
// Note: It's possible and legal for a provider to return the integrity
// violation at Execute time.
m_hr = oBatch.SetAndExecute(IID_IMultipleResults);
// Test DB_E_INTEGRITYVIOLATION first so if an error is returned at Execute
// time but it's not DB_E_INTEGRITYVIOLATION our failure will indicate
// that as the preferred error.
TEST2C_(m_hr, DB_E_INTEGRITYVIOLATION, S_OK);
if (m_hr == S_OK)
{
while ( (m_hr = (oBatch.m_pIMultResults)->GetResult(NULL,
rgFlag[0],
rgIID[0],
&oBatch.m_cRowsGetResultAffected,
(IUnknown **)&(oBatch.m_pIRowset)) )
!= DB_S_NORESULT)
{
iResult++;
// Results 1 and 3 are rowsets
if (iResult != 2)
{
TESTC_(m_hr, S_OK);
TESTC(oBatch.m_pIRowset != NULL);
TESTC_(oBatch.VerifySelectRowset(rgIID[0], oBatch.m_pIRowset, ISROWSET), S_OK);
SAFE_RELEASE(oBatch.m_pIRowset);
}
else
{
// Result 2 should be our integrity violation
TESTC_(m_hr, DB_E_INTEGRITYVIOLATION);
TESTC(oBatch.m_pIRowset == NULL);
SAFE_RELEASE(oBatch.m_pIRowset); // Just in case it was returned.
}
}
//Make sure we did end correctly
CHECK(m_hr, DB_S_NORESULT);
COMPARE(iResult, 3);
//Now make sure we get the same return code again
TESTC_((oBatch.m_pIMultResults)->GetResult(NULL,
rgFlag[0],
rgIID[0],
&oBatch.m_cRowsGetResultAffected,
(IUnknown **)&(oBatch.m_pIRowset)), DB_S_NORESULT);
}
fResult = TEST_PASS;
CLEANUP:
oBatch.ReleaseIRowset();
oBatch.ReleaseIMultipleResults();
return fResult;
}
// }} TCW_VAR_PROTOTYPE_END
// {{ TCW_VAR_PROTOTYPE(53)
//*-----------------------------------------------------------------------
// @mfunc DB_E_NOAGGREGATION: Aggregated Result asking for IID != IID_IUnknown
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCGetResult_Rowset::Variation_53()
{
HRESULT hrExecute = E_FAIL;
ULONG iProp;
ULONG cInterfaces;
INTERFACEMAP * prgInterfaces = NULL;
ESQLSTMT rgeSQLStmts[] = {ESELECT, ESELECT, ESELECT};
const ULONG ceSQLStmts = sizeof(rgeSQLStmts) / sizeof(ESQLSTMT);
DECL_FLAGSANDIIDS(ceSQLStmts)
CMultResults * pMultResults = NULL;
IRowset * pIRowset = NULL;
TESTRESULT testresult = TEST_PASS;
HRESULT hr = E_FAIL;
CAggregate* pAggregate = NULL;
IUnknown * pIAggUnknown = NULL;
i=0;
// Get the list of rowset interfaces/properties
TESTC(GetInterfaceArray(ISROWSET ? ROWSET_INTERFACE : ROW_INTERFACE, &cInterfaces, &prgInterfaces));
for (iProp=0; iProp < cInterfaces; iProp++)
{
TESTC_(SetUpGetResult(&pMultResults, ceSQLStmts, rgeSQLStmts, rgFlag), S_OK);
for (i=0; i<ceSQLStmts+1; i++)
{
// IID_IUnknown is a success case and tested in a different variation
if (*prgInterfaces[iProp].pIID == IID_IUnknown)
continue;
pAggregate = new CAggregate;
TESTC(pAggregate != NULL);
hr = pMultResults->m_pIMultResults->GetResult(pAggregate,
rgFlag[0],
*prgInterfaces[iProp].pIID,
&pMultResults->m_cRowsGetResultAffected,
(IUnknown **)&pIAggUnknown);
if (hr != DB_E_NOAGGREGATION)
odtLog << prgInterfaces[iProp].pwszName << L"\n";
TESTC_(hr, DB_E_NOAGGREGATION);
SAFE_RELEASE(pIAggUnknown);
SAFE_DELETE(pAggregate);
}
SAFE_RELEASE(pMultResults->m_pIMultResults);
SAFE_DELETE(pMultResults);
}
testresult = TEST_PASS;
CLEANUP:
SAFE_RELEASE(pIRowset);
SAFE_RELEASE(pIAggUnknown);
SAFE_DELETE(pAggregate);
if (pMultResults)
SAFE_RELEASE(pMultResults->m_pIMultResults);
SAFE_DELETE(pMultResults);
return testresult;
}
// }} TCW_VAR_PROTOTYPE_END
// {{ TCW_VAR_PROTOTYPE(54)
//*-----------------------------------------------------------------------
// @mfunc S_OK: IMultipleResults with compute by clause
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCGetResult_Rowset::Variation_54()
{
// This variation repros a failure that occurred in one provider when a compute
// clause was used with multiple results statement asking for IID_IRowset
// and not retrieving the results, just releasing the rowset.
IRowset * pIRowset = NULL;
IRow * pIRow = NULL;
BOOL fResults = FALSE;
CMultResults * pMultResults = NULL;
ESQLSTMT rgeSQLStmts[] = {
ECOMPUTESUM,
ECOMPUTESUM,
};
const ULONG ceSQLStmts = sizeof(rgeSQLStmts) / sizeof(ESQLSTMT);
DECL_FLAGSANDIIDS(ceSQLStmts)
BOOL fResult = TEST_FAIL;
HROW rghRow[1] = {DB_NULL_HROW};
HROW * prghRow = (HROW *)rghRow;
DBCOUNTITEM cRowsObtained = 0;
HRESULT hr = E_FAIL;
//Get an IMultipleResults interface, use our own SQLStmts
TESTC_(SetUpGetResult(&pMultResults, ceSQLStmts, rgeSQLStmts, rgFlag), S_OK);
// Release the multiple results object obtained above
SAFE_RELEASE(pMultResults->m_pIMultResults);
TESTC_(SetCommandText(m_pIMalloc,m_pICommandText,m_pSelectTable,NULL,eSQL,SELECT_ALLFROMTBL,pMultResults->GetSQLStmt()), S_OK);
if(ISROWSET)
{
TESTC_(m_pICommandText->Execute(NULL, IID_IRowset, NULL, NULL,(IUnknown **)&pIRowset), S_OK);
// If we don't retrieve any rows from the rowset we won't repro the failure
for (; (hr = pIRowset->GetNextRows(NULL, 0, 1, &cRowsObtained, &prghRow)) == S_OK;)
CHECK(pIRowset->ReleaseRows(1, rghRow, NULL, NULL, NULL), S_OK);
TESTC_(hr, DB_S_ENDOFROWSET);
}
else
{
TESTC_(m_pICommandText->Execute(NULL, IID_IRow, NULL, NULL,(IUnknown **)&pIRow), S_OK);
}
fResult = TEST_PASS;
CLEANUP:
// Failure actually occurs on release of the rowset.
SAFE_RELEASE(pIRowset);
SAFE_RELEASE(pIRow);
delete pMultResults;
return fResult;
}
// }} TCW_VAR_PROTOTYPE_END
// {{ TCW_VAR_PROTOTYPE(55)
//*-----------------------------------------------------------------------
// @mfunc DBPROP_SKIPROWCOUNTRESULTS (default): Ask for same type of object.
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCGetResult_Rowset::Variation_55()
{
TBEGIN
IUnknown* pRowset = NULL;
BOOL fSkipRC = FALSE;
CMultResults * pMultResults = NULL;
ICommandProperties* pICP = NULL;
ESQLSTMT rgeSQLStmts[] = {
EINSERT,
EUPDATE,
EDELETE,
ESELECT,
EUPDATE,
ESELECT,
EINSERT
};
const ULONG ceSQLStmts = sizeof(rgeSQLStmts) / sizeof(ESQLSTMT);
DECL_FLAGSANDIIDS(ceSQLStmts)
if(GetProperty(DBPROP_SKIPROWCOUNTRESULTS, DBPROPSET_ROWSET, m_pICommandText))
fSkipRC = TRUE;
//Get an IMultipleResults interface
TESTC_(SetUpGetResult(&pMultResults, ceSQLStmts, rgeSQLStmts, rgFlag), S_OK)
if(fSkipRC)
{
TESTC_(pMultResults->m_pIMultResults->GetResult(NULL,
rgFlag[3], rgIID[3], &pMultResults->m_cRowsGetResultAffected,
(IUnknown **)&pRowset), S_OK)
COMPARE(pRowset != NULL, TRUE);
CHECK(pMultResults->VerifySelectRowset(rgIID[3], pRowset, ISROWSET), S_OK);
SAFE_RELEASE(pRowset);
TESTC_(pMultResults->m_pIMultResults->GetResult(NULL,
rgFlag[5], rgIID[5], &pMultResults->m_cRowsGetResultAffected,
(IUnknown **)&pRowset), S_OK)
COMPARE(pRowset != NULL, TRUE);
CHECK(pMultResults->VerifySelectRowset(rgIID[5], pRowset, ISROWSET), S_OK);
SAFE_RELEASE(pRowset);
TESTC_(pMultResults->m_pIMultResults->GetResult(NULL,
rgFlag[5], rgIID[5], &pMultResults->m_cRowsGetResultAffected,
(IUnknown **)&pRowset), DB_S_NORESULT)
SAFE_RELEASE(pRowset);
}
else
{
TESTC_(pMultResults->m_pIMultResults->GetResult(NULL,
rgFlag[0], rgIID[0], &pMultResults->m_cRowsGetResultAffected,
(IUnknown **)&pRowset), S_OK)
COMPARE(pRowset, NULL);
COMPARE(pMultResults->IsGetResultRowsAffectedRight(0), TRUE);
SAFE_RELEASE(pRowset);
TESTC_(pMultResults->m_pIMultResults->GetResult(NULL,
rgFlag[1], rgIID[1], &pMultResults->m_cRowsGetResultAffected,
(IUnknown **)&pRowset), S_OK)
COMPARE(pRowset, NULL);
COMPARE(pMultResults->IsGetResultRowsAffectedRight(1), TRUE);
SAFE_RELEASE(pRowset);
TESTC_(pMultResults->m_pIMultResults->GetResult(NULL,
rgFlag[2], rgIID[2], &pMultResults->m_cRowsGetResultAffected,
(IUnknown **)&pRowset), S_OK)
COMPARE(pRowset, NULL);
COMPARE(pMultResults->IsGetResultRowsAffectedRight(2), TRUE);
SAFE_RELEASE(pRowset);
TESTC_(pMultResults->m_pIMultResults->GetResult(NULL,
rgFlag[3], rgIID[3], &pMultResults->m_cRowsGetResultAffected,
(IUnknown **)&pRowset), S_OK)
COMPARE(pRowset != NULL, TRUE);
CHECK(pMultResults->VerifySelectRowset(rgIID[3], pRowset, ISROWSET), S_OK);
SAFE_RELEASE(pRowset);
TESTC_(pMultResults->m_pIMultResults->GetResult(NULL,
rgFlag[4], rgIID[4], &pMultResults->m_cRowsGetResultAffected,
(IUnknown **)&pRowset), S_OK)
COMPARE(pRowset, NULL);
COMPARE(pMultResults->IsGetResultRowsAffectedRight(4), TRUE);
SAFE_RELEASE(pRowset);
TESTC_(pMultResults->m_pIMultResults->GetResult(NULL,
rgFlag[5], rgIID[5], &pMultResults->m_cRowsGetResultAffected,
(IUnknown **)&pRowset), S_OK)
COMPARE(pRowset != NULL, TRUE);
CHECK(pMultResults->VerifySelectRowset(rgIID[5], pRowset, ISROWSET), S_OK);
SAFE_RELEASE(pRowset);
TESTC_(pMultResults->m_pIMultResults->GetResult(NULL,
rgFlag[6], rgIID[6], &pMultResults->m_cRowsGetResultAffected,
(IUnknown **)&pRowset), S_OK)
COMPARE(pRowset, NULL);
COMPARE(pMultResults->IsGetResultRowsAffectedRight(6), TRUE);
SAFE_RELEASE(pRowset);
TESTC_(pMultResults->m_pIMultResults->GetResult(NULL,
rgFlag[6], rgIID[6], &pMultResults->m_cRowsGetResultAffected,
(IUnknown **)&pRowset), DB_S_NORESULT)
SAFE_RELEASE(pRowset);
}
CLEANUP:
SAFE_RELEASE(pICP);
SAFE_RELEASE(pRowset);
if (pMultResults)
{
pMultResults->ReleaseIMultipleResults();
delete pMultResults;
}
SetRowsetPropertyDefault(DBPROP_SKIPROWCOUNTRESULTS);
TRETURN
}
// }} TCW_VAR_PROTOTYPE_END
// {{ TCW_VAR_PROTOTYPE(56)
//*-----------------------------------------------------------------------
// @mfunc DBPROP_SKIPROWCOUNTRESULTS (default): Ask for mixed types of objects.
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCGetResult_Rowset::Variation_56()
{
TBEGIN
IUnknown* pRowset = NULL;
BOOL fSkipRC = FALSE;
CMultResults * pMultResults = NULL;
ICommandProperties* pICP = NULL;
ESQLSTMT rgeSQLStmts[] = {
ESELECT,
EINSERT,
ESELECT,
EUPDATE,
ESELECT,
EDELETE,
ESELECT
};
const ULONG ceSQLStmts = sizeof(rgeSQLStmts) / sizeof(ESQLSTMT);
DECL_FLAGSANDIIDS(ceSQLStmts)
TESTC_PROVIDER(g_fRowSupp)
if(GetProperty(DBPROP_SKIPROWCOUNTRESULTS, DBPROPSET_ROWSET, m_pICommandText))
fSkipRC = TRUE;
//Setup IIDs and Flags to use.
rgFlag[0] = ISROWSET ? DBRESULTFLAG_ROWSET : DBRESULTFLAG_DEFAULT;
rgIID[0] = ISROWSET ? IID_IAccessor : IID_IColumnsInfo;
rgFlag[1] = ISROWSET ? DBRESULTFLAG_DEFAULT : DBRESULTFLAG_ROW;
rgIID[1] = ISROWSET ? IID_IConvertType : IID_IGetSession;
rgFlag[2] = ISROWSET ? DBRESULTFLAG_ROW : DBRESULTFLAG_ROWSET;
rgIID[2] = ISROWSET ? IID_IGetSession : IID_IRowsetInfo;
rgFlag[3] = ISROWSET ? DBRESULTFLAG_ROW : DBRESULTFLAG_DEFAULT;
rgIID[3] = ISROWSET ? IID_IGetSession : IID_IColumnsInfo;
rgFlag[4] = ISROWSET ? DBRESULTFLAG_DEFAULT : DBRESULTFLAG_ROW;
rgIID[4] = ISROWSET ? IID_IUnknown : IID_IColumnsInfo;
rgFlag[5] = ISROWSET ? DBRESULTFLAG_ROW : DBRESULTFLAG_ROWSET;
rgIID[5] = ISROWSET ? IID_IRow : IID_IConvertType;
rgFlag[6] = ISROWSET ? DBRESULTFLAG_ROWSET : DBRESULTFLAG_DEFAULT;
rgIID[6] = ISROWSET ? IID_IRowsetInfo : IID_IColumnsInfo;
//Get an IMultipleResults interface
TESTC_(SetUpGetResult(&pMultResults, ceSQLStmts, rgeSQLStmts, rgFlag), S_OK)
if(fSkipRC)
{
TESTC_(pMultResults->m_pIMultResults->GetResult(NULL,
rgFlag[0], rgIID[0], &pMultResults->m_cRowsGetResultAffected,
(IUnknown **)&pRowset), S_OK)
COMPARE(pRowset != NULL, TRUE);
CHECK(pMultResults->VerifySelectRowset(rgIID[0], pRowset, TRUE), S_OK);
SAFE_RELEASE(pRowset);
TESTC_(pMultResults->m_pIMultResults->GetResult(NULL,
rgFlag[2], rgIID[2], &pMultResults->m_cRowsGetResultAffected,
(IUnknown **)&pRowset), S_OK)
COMPARE(pRowset != NULL, TRUE);
CHECK(pMultResults->VerifySelectRowset(rgIID[2], pRowset, !(ISROWSET)), S_OK);
SAFE_RELEASE(pRowset);
TESTC_(pMultResults->m_pIMultResults->GetResult(NULL,
rgFlag[4], rgIID[4], &pMultResults->m_cRowsGetResultAffected,
(IUnknown **)&pRowset), S_OK)
COMPARE(pRowset != NULL, TRUE);
CHECK(pMultResults->VerifySelectRowset(rgIID[4], pRowset, ISROWSET), S_OK);
SAFE_RELEASE(pRowset);
TESTC_(pMultResults->m_pIMultResults->GetResult(NULL,
rgFlag[6], rgIID[6], &pMultResults->m_cRowsGetResultAffected,
(IUnknown **)&pRowset), S_OK)
COMPARE(pRowset != NULL, TRUE);
CHECK(pMultResults->VerifySelectRowset(rgIID[6], pRowset, TRUE), S_OK);
SAFE_RELEASE(pRowset);
TESTC_(pMultResults->m_pIMultResults->GetResult(NULL,
rgFlag[6], rgIID[6], &pMultResults->m_cRowsGetResultAffected,
(IUnknown **)&pRowset), DB_S_NORESULT)
SAFE_RELEASE(pRowset);
}
else
{
TESTC_(pMultResults->m_pIMultResults->GetResult(NULL,
rgFlag[0], rgIID[0], &pMultResults->m_cRowsGetResultAffected,
(IUnknown **)&pRowset), S_OK)
COMPARE(pRowset != NULL, TRUE);
CHECK(pMultResults->VerifySelectRowset(rgIID[0], pRowset, TRUE), S_OK);
SAFE_RELEASE(pRowset);
TESTC_(pMultResults->m_pIMultResults->GetResult(NULL,
rgFlag[1], rgIID[1], &pMultResults->m_cRowsGetResultAffected,
(IUnknown **)&pRowset), S_OK)
COMPARE(pRowset, NULL);
COMPARE(pMultResults->IsGetResultRowsAffectedRight(1), TRUE);
SAFE_RELEASE(pRowset);
TESTC_(pMultResults->m_pIMultResults->GetResult(NULL,
rgFlag[2], rgIID[2], &pMultResults->m_cRowsGetResultAffected,
(IUnknown **)&pRowset), S_OK)
COMPARE(pRowset != NULL, TRUE);
CHECK(pMultResults->VerifySelectRowset(rgIID[2], pRowset, !(ISROWSET)), S_OK);
SAFE_RELEASE(pRowset);
TESTC_(pMultResults->m_pIMultResults->GetResult(NULL,
rgFlag[3], rgIID[3], &pMultResults->m_cRowsGetResultAffected,
(IUnknown **)&pRowset), S_OK)
COMPARE(pRowset, NULL);
COMPARE(pMultResults->IsGetResultRowsAffectedRight(3), TRUE);
SAFE_RELEASE(pRowset);
TESTC_(pMultResults->m_pIMultResults->GetResult(NULL,
rgFlag[4], rgIID[4], &pMultResults->m_cRowsGetResultAffected,
(IUnknown **)&pRowset), S_OK)
COMPARE(pRowset != NULL, TRUE);
CHECK(pMultResults->VerifySelectRowset(rgIID[4], pRowset, ISROWSET), S_OK);
SAFE_RELEASE(pRowset);
TESTC_(pMultResults->m_pIMultResults->GetResult(NULL,
rgFlag[5], rgIID[5], &pMultResults->m_cRowsGetResultAffected,
(IUnknown **)&pRowset), S_OK)
COMPARE(pRowset, NULL);
COMPARE(pMultResults->IsGetResultRowsAffectedRight(5), TRUE);
SAFE_RELEASE(pRowset);
TESTC_(pMultResults->m_pIMultResults->GetResult(NULL,
rgFlag[6], rgIID[6], &pMultResults->m_cRowsGetResultAffected,
(IUnknown **)&pRowset), S_OK)
COMPARE(pRowset != NULL, TRUE);
CHECK(pMultResults->VerifySelectRowset(rgIID[6], pRowset, TRUE), S_OK);
SAFE_RELEASE(pRowset);
TESTC_(pMultResults->m_pIMultResults->GetResult(NULL,
rgFlag[6], rgIID[6], &pMultResults->m_cRowsGetResultAffected,
(IUnknown **)&pRowset), DB_S_NORESULT)
SAFE_RELEASE(pRowset);
}
CLEANUP:
SAFE_RELEASE(pICP);
SAFE_RELEASE(pRowset);
if (pMultResults)
{
pMultResults->ReleaseIMultipleResults();
delete pMultResults;
}
SetRowsetPropertyDefault(DBPROP_SKIPROWCOUNTRESULTS);
TRETURN
}
// }} TCW_VAR_PROTOTYPE_END
// {{ TCW_VAR_PROTOTYPE(57)
//*-----------------------------------------------------------------------
// @mfunc DBPROP_SKIPROWCOUNTRESULTS (true): Ask for same type of object.
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCGetResult_Rowset::Variation_57()
{
TBEGIN
IUnknown* pRowset = NULL;
VARIANT_BOOL bSkipRC = VARIANT_FALSE;
CMultResults * pMultResults = NULL;
ICommandProperties* pICP = NULL;
ESQLSTMT rgeSQLStmts[] = {
EINSERT,
EUPDATE,
EDELETE,
ESELECT,
EUPDATE,
ESELECT,
EINSERT
};
const ULONG ceSQLStmts = sizeof(rgeSQLStmts) / sizeof(ESQLSTMT);
DECL_FLAGSANDIIDS(ceSQLStmts)
if(!GetProperty(DBPROP_SKIPROWCOUNTRESULTS, DBPROPSET_ROWSET, m_pICommandText, &bSkipRC))
{
odtLog<<L"INFO: DBPROP_SKIPROWCOUNTRESULTS is not supported.\n";
goto CLEANUP;
}
if(S_OK != SetRowsetPropertyOn(DBPROP_SKIPROWCOUNTRESULTS))
{
odtLog<<L"INFO: DBPROP_SKIPROWCOUNTRESULTS could not be set to TRUE.\n";
COMPAREW(TRUE, FALSE); //Throw a warning.
goto CLEANUP;
}
//Get an IMultipleResults interface
TESTC_(SetUpGetResult(&pMultResults, ceSQLStmts, rgeSQLStmts, rgFlag), S_OK)
TESTC_(pMultResults->m_pIMultResults->GetResult(NULL,
rgFlag[3], rgIID[3], &pMultResults->m_cRowsGetResultAffected,
(IUnknown **)&pRowset), S_OK)
COMPARE(pRowset != NULL, TRUE);
CHECK(pMultResults->VerifySelectRowset(rgIID[3], pRowset, ISROWSET), S_OK);
SAFE_RELEASE(pRowset);
TESTC_(pMultResults->m_pIMultResults->GetResult(NULL,
rgFlag[5], rgIID[5], &pMultResults->m_cRowsGetResultAffected,
(IUnknown **)&pRowset), S_OK)
COMPARE(pRowset != NULL, TRUE);
CHECK(pMultResults->VerifySelectRowset(rgIID[5], pRowset, ISROWSET), S_OK);
SAFE_RELEASE(pRowset);
TESTC_(pMultResults->m_pIMultResults->GetResult(NULL,
rgFlag[5], rgIID[5], &pMultResults->m_cRowsGetResultAffected,
(IUnknown **)&pRowset), DB_S_NORESULT)
SAFE_RELEASE(pRowset);
CLEANUP:
SAFE_RELEASE(pICP);
SAFE_RELEASE(pRowset);
if (pMultResults)
{
pMultResults->ReleaseIMultipleResults();
delete pMultResults;
}
SetRowsetPropertyDefault(DBPROP_SKIPROWCOUNTRESULTS);
TRETURN
}
// }} TCW_VAR_PROTOTYPE_END
// {{ TCW_VAR_PROTOTYPE(58)
//*-----------------------------------------------------------------------
// @mfunc DBPROP_SKIPROWCOUNTRESULTS (true): Ask for mixed types of objects.
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCGetResult_Rowset::Variation_58()
{
TBEGIN
IUnknown* pRowset = NULL;
VARIANT_BOOL bSkipRC = VARIANT_FALSE;
CMultResults * pMultResults = NULL;
ICommandProperties* pICP = NULL;
ESQLSTMT rgeSQLStmts[] = {
ESELECT,
EINSERT,
ESELECT,
EUPDATE,
ESELECT,
EDELETE,
ESELECT
};
const ULONG ceSQLStmts = sizeof(rgeSQLStmts) / sizeof(ESQLSTMT);
DECL_FLAGSANDIIDS(ceSQLStmts)
TESTC_PROVIDER(g_fRowSupp)
if(!GetProperty(DBPROP_SKIPROWCOUNTRESULTS, DBPROPSET_ROWSET, m_pICommandText, &bSkipRC))
{
odtLog<<L"INFO: DBPROP_SKIPROWCOUNTRESULTS is not supported.\n";
goto CLEANUP;
}
if(S_OK != SetRowsetPropertyOn(DBPROP_SKIPROWCOUNTRESULTS))
{
odtLog<<L"INFO: DBPROP_SKIPROWCOUNTRESULTS could not be set to TRUE.\n";
COMPAREW(TRUE, FALSE); //Throw a warning.
goto CLEANUP;
}
//Setup IIDs and Flags to use.
rgFlag[0] = ISROWSET ? DBRESULTFLAG_ROWSET : DBRESULTFLAG_DEFAULT;
rgIID[0] = ISROWSET ? IID_IAccessor : IID_IColumnsInfo;
rgFlag[1] = ISROWSET ? DBRESULTFLAG_DEFAULT : DBRESULTFLAG_ROW;
rgIID[1] = ISROWSET ? IID_IConvertType : IID_IGetSession;
rgFlag[2] = ISROWSET ? DBRESULTFLAG_ROW : DBRESULTFLAG_ROWSET;
rgIID[2] = ISROWSET ? IID_IGetSession : IID_IRowsetInfo;
rgFlag[3] = ISROWSET ? DBRESULTFLAG_ROW : DBRESULTFLAG_DEFAULT;
rgIID[3] = ISROWSET ? IID_IGetSession : IID_IColumnsInfo;
rgFlag[4] = ISROWSET ? DBRESULTFLAG_DEFAULT : DBRESULTFLAG_ROW;
rgIID[4] = ISROWSET ? IID_IUnknown : IID_IColumnsInfo;
rgFlag[5] = ISROWSET ? DBRESULTFLAG_ROW : DBRESULTFLAG_ROWSET;
rgIID[5] = ISROWSET ? IID_IRow : IID_IConvertType;
rgFlag[6] = ISROWSET ? DBRESULTFLAG_ROWSET : DBRESULTFLAG_DEFAULT;
rgIID[6] = ISROWSET ? IID_IRowsetInfo : IID_IColumnsInfo;
//Get an IMultipleResults interface
TESTC_(SetUpGetResult(&pMultResults, ceSQLStmts, rgeSQLStmts, rgFlag), S_OK)
TESTC_(pMultResults->m_pIMultResults->GetResult(NULL,
rgFlag[0], rgIID[0], &pMultResults->m_cRowsGetResultAffected,
(IUnknown **)&pRowset), S_OK)
COMPARE(pRowset != NULL, TRUE);
CHECK(pMultResults->VerifySelectRowset(rgIID[0], pRowset, TRUE), S_OK);
SAFE_RELEASE(pRowset);
TESTC_(pMultResults->m_pIMultResults->GetResult(NULL,
rgFlag[2], rgIID[2], &pMultResults->m_cRowsGetResultAffected,
(IUnknown **)&pRowset), S_OK)
COMPARE(pRowset != NULL, TRUE);
CHECK(pMultResults->VerifySelectRowset(rgIID[2], pRowset, !(ISROWSET)), S_OK);
SAFE_RELEASE(pRowset);
TESTC_(pMultResults->m_pIMultResults->GetResult(NULL,
rgFlag[4], rgIID[4], &pMultResults->m_cRowsGetResultAffected,
(IUnknown **)&pRowset), S_OK)
COMPARE(pRowset != NULL, TRUE);
CHECK(pMultResults->VerifySelectRowset(rgIID[4], pRowset, ISROWSET), S_OK);
SAFE_RELEASE(pRowset);
TESTC_(pMultResults->m_pIMultResults->GetResult(NULL,
rgFlag[6], rgIID[6], &pMultResults->m_cRowsGetResultAffected,
(IUnknown **)&pRowset), S_OK)
COMPARE(pRowset != NULL, TRUE);
CHECK(pMultResults->VerifySelectRowset(rgIID[6], pRowset, TRUE), S_OK);
SAFE_RELEASE(pRowset);
TESTC_(pMultResults->m_pIMultResults->GetResult(NULL,
rgFlag[6], rgIID[6], &pMultResults->m_cRowsGetResultAffected,
(IUnknown **)&pRowset), DB_S_NORESULT)
SAFE_RELEASE(pRowset);
CLEANUP:
SAFE_RELEASE(pICP);
SAFE_RELEASE(pRowset);
if (pMultResults)
{
pMultResults->ReleaseIMultipleResults();
delete pMultResults;
}
SetRowsetPropertyDefault(DBPROP_SKIPROWCOUNTRESULTS);
TRETURN
}
// }} TCW_VAR_PROTOTYPE_END
// {{ TCW_VAR_PROTOTYPE(59)
//*-----------------------------------------------------------------------
// @mfunc DBPROP_IRow (true) : Get ROW objs
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCGetResult_Rowset::Variation_59()
{
TBEGIN
HRESULT hr = E_FAIL;
IUnknown* pRowset = NULL;
CMultResults * pMultResults = NULL;
CBatch oBatch(m_pIDBCreateCommand,
m_pICommandText,
m_pSelectTable,
m_pChangeTable);
ESQLSTMT rgeSQLStmts[] = {
EINSERT,
EUPDATE,
ESELECT,
EDELETE,
ESELECT,
ESELECT,
ESELECT
};
const ULONG ceSQLStmts = sizeof(rgeSQLStmts) / sizeof(ESQLSTMT);
DECL_FLAGSANDIIDS(ceSQLStmts)
//Setup IIDs and Flags to use.
rgFlag[0] = ISROWSET ? DBRESULTFLAG_ROW : DBRESULTFLAG_DEFAULT;
rgIID[0] = ISROWSET ? IID_IGetSession : IID_IColumnsInfo;
rgFlag[1] = ISROWSET ? DBRESULTFLAG_DEFAULT : DBRESULTFLAG_ROW;
rgIID[1] = ISROWSET ? IID_IRow : IID_IColumnsInfo;
rgFlag[2] = ISROWSET ? DBRESULTFLAG_ROW : DBRESULTFLAG_DEFAULT;
rgIID[2] = ISROWSET ? IID_IUnknown : IID_IUnknown;
rgFlag[3] = ISROWSET ? DBRESULTFLAG_ROW : DBRESULTFLAG_DEFAULT;
rgIID[3] = ISROWSET ? IID_IGetSession : IID_IColumnsInfo;
rgFlag[4] = ISROWSET ? DBRESULTFLAG_DEFAULT : DBRESULTFLAG_ROW;
rgIID[4] = ISROWSET ? IID_IGetSession : IID_IColumnsInfo;
rgFlag[5] = ISROWSET ? DBRESULTFLAG_DEFAULT : DBRESULTFLAG_ROW;
rgIID[5] = ISROWSET ? IID_IRow : IID_IConvertType;
rgFlag[6] = ISROWSET ? DBRESULTFLAG_ROW : DBRESULTFLAG_DEFAULT;
rgIID[6] = ISROWSET ? IID_IRowset : IID_IAccessor;
TESTC_PROVIDER(g_fRowSupp)
TESTC_(hr = SetRowsetPropertyOn(DBPROP_IRow), S_OK)
//Get an IMultipleResults interface
TESTC_(SetUpGetResult(&pMultResults, ceSQLStmts, rgeSQLStmts, rgFlag), S_OK)
//EINSERT
TESTC_(pMultResults->m_pIMultResults->GetResult(NULL,
rgFlag[0], rgIID[0], &pMultResults->m_cRowsGetResultAffected,
(IUnknown **)&pRowset), S_OK)
COMPARE(pRowset, NULL);
COMPARE(pMultResults->IsGetResultRowsAffectedRight(0), TRUE);
SAFE_RELEASE(pRowset);
//EUPDATE
TESTC_(pMultResults->m_pIMultResults->GetResult(NULL,
rgFlag[1], rgIID[1], &pMultResults->m_cRowsGetResultAffected,
(IUnknown **)&pRowset), S_OK)
COMPARE(pRowset, NULL);
COMPARE(pMultResults->IsGetResultRowsAffectedRight(1), TRUE);
SAFE_RELEASE(pRowset);
//ESELECT
TESTC_(pMultResults->m_pIMultResults->GetResult(NULL,
rgFlag[2], rgIID[2], &pMultResults->m_cRowsGetResultAffected,
(IUnknown **)&pRowset), S_OK)
COMPARE(pRowset != NULL, TRUE);
CHECK(pMultResults->VerifySelectRowset(rgIID[2], pRowset, FALSE), S_OK);
SAFE_RELEASE(pRowset);
//EDELETE
TESTC_(pMultResults->m_pIMultResults->GetResult(NULL,
rgFlag[3], rgIID[3], &pMultResults->m_cRowsGetResultAffected,
(IUnknown **)&pRowset), S_OK)
COMPARE(pRowset, NULL);
COMPARE(pMultResults->IsGetResultRowsAffectedRight(3), TRUE);
SAFE_RELEASE(pRowset);
//ESELECT
TESTC_(pMultResults->m_pIMultResults->GetResult(NULL,
rgFlag[4], rgIID[4], &pMultResults->m_cRowsGetResultAffected,
(IUnknown **)&pRowset), S_OK)
COMPARE(pRowset != NULL, TRUE);
CHECK(pMultResults->VerifySelectRowset(rgIID[4], pRowset, FALSE), S_OK);
SAFE_RELEASE(pRowset);
//ESELECT
TESTC_(pMultResults->m_pIMultResults->GetResult(NULL,
rgFlag[5], rgIID[5], &pMultResults->m_cRowsGetResultAffected,
(IUnknown **)&pRowset), S_OK)
COMPARE(pRowset != NULL, TRUE);
CHECK(pMultResults->VerifySelectRowset(rgIID[5], pRowset, FALSE), S_OK);
SAFE_RELEASE(pRowset);
//ESELECT
TESTC_(pMultResults->m_pIMultResults->GetResult(NULL,
rgFlag[6], rgIID[6], &pMultResults->m_cRowsGetResultAffected,
(IUnknown **)&pRowset), E_NOINTERFACE)
COMPARE(pRowset, NULL);
//END of results.
TESTC_(pMultResults->m_pIMultResults->GetResult(NULL,
rgFlag[5], rgIID[5], &pMultResults->m_cRowsGetResultAffected,
(IUnknown **)&pRowset), DB_S_NORESULT)
SAFE_RELEASE(pRowset);
CLEANUP:
SAFE_RELEASE(pRowset);
if (pMultResults)
{
pMultResults->ReleaseIMultipleResults();
delete pMultResults;
}
SetRowsetPropertyDefault(DBPROP_IRow);
TRETURN
}
// }} TCW_VAR_PROTOTYPE_END
// {{ TCW_VAR_PROTOTYPE(60)
//*-----------------------------------------------------------------------
// @mfunc DBPROP_IRow (true) : Set as optional and flag = ROWSET
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCGetResult_Rowset::Variation_60()
{
TBEGIN
HRESULT hr = E_FAIL;
IUnknown* pRowset = NULL;
CMultResults * pMultResults = NULL;
CBatch oBatch(m_pIDBCreateCommand,
m_pICommandText,
m_pSelectTable,
m_pChangeTable);
ESQLSTMT rgeSQLStmts[] = {
ESELECT,
ESELECT,
ESELECT
};
const ULONG ceSQLStmts = sizeof(rgeSQLStmts) / sizeof(ESQLSTMT);
DECL_FLAGSANDIIDS(ceSQLStmts)
TESTC_PROVIDER(g_fRowSupp)
//Setup IIDs and Flags to use.
/*
rgFlag[0] = ISROWSET ? DBRESULTFLAG_ROW : DBRESULTFLAG_DEFAULT;
rgIID[0] = ISROWSET ? IID_IGetSession : IID_IColumnsInfo;
rgFlag[1] = ISROWSET ? DBRESULTFLAG_DEFAULT : DBRESULTFLAG_ROW;
rgIID[1] = ISROWSET ? IID_IRow : IID_IColumnsInfo;
rgFlag[1] = ISROWSET ? DBRESULTFLAG_DEFAULT : DBRESULTFLAG_ROW;
rgIID[1] = ISROWSET ? IID_IRow : IID_IColumnsInfo;
TESTC_(hr = SetRowsetPropertyOn(DBPROP_IRow), S_OK)
//Get an IMultipleResults interface
TESTC_(SetUpGetResult(&pMultResults, ceSQLStmts, rgeSQLStmts, rgFlag), S_OK)
//ESELECT
TESTC_(pMultResults->m_pIMultResults->GetResult(NULL,
rgFlag[2], rgIID[2], &pMultResults->m_cRowsGetResultAffected,
(IUnknown **)&pRowset), S_OK)
COMPARE(pRowset != NULL, TRUE);
COMPARE(pMultResults->VerifySelectRowset(rgIID[2], pRowset, FALSE), TRUE);
SAFE_RELEASE(pRowset);
//ESELECT
TESTC_(pMultResults->m_pIMultResults->GetResult(NULL,
rgFlag[2], rgIID[2], &pMultResults->m_cRowsGetResultAffected,
(IUnknown **)&pRowset), S_OK)
COMPARE(pRowset != NULL, TRUE);
COMPARE(pMultResults->VerifySelectRowset(rgIID[2], pRowset, FALSE), TRUE);
SAFE_RELEASE(pRowset);
//ESELECT
TESTC_(pMultResults->m_pIMultResults->GetResult(NULL,
rgFlag[2], rgIID[2], &pMultResults->m_cRowsGetResultAffected,
(IUnknown **)&pRowset), S_OK)
COMPARE(pRowset != NULL, TRUE);
COMPARE(pMultResults->VerifySelectRowset(rgIID[2], pRowset, FALSE), TRUE);
SAFE_RELEASE(pRowset);
//ESELECT
TESTC_(pMultResults->m_pIMultResults->GetResult(NULL,
rgFlag[2], rgIID[2], &pMultResults->m_cRowsGetResultAffected,
(IUnknown **)&pRowset), S_OK)
COMPARE(pRowset != NULL, TRUE);
COMPARE(pMultResults->VerifySelectRowset(rgIID[2], pRowset, FALSE), TRUE);
SAFE_RELEASE(pRowset);
//ESELECT
TESTC_(pMultResults->m_pIMultResults->GetResult(NULL,
rgFlag[2], rgIID[2], &pMultResults->m_cRowsGetResultAffected,
(IUnknown **)&pRowset), S_OK)
COMPARE(pRowset != NULL, TRUE);
COMPARE(pMultResults->VerifySelectRowset(rgIID[2], pRowset, FALSE), TRUE);
SAFE_RELEASE(pRowset);
//ESELECT
TESTC_(pMultResults->m_pIMultResults->GetResult(NULL,
rgFlag[2], rgIID[2], &pMultResults->m_cRowsGetResultAffected,
(IUnknown **)&pRowset), S_OK)
COMPARE(pRowset != NULL, TRUE);
COMPARE(pMultResults->VerifySelectRowset(rgIID[2], pRowset, FALSE), TRUE);
SAFE_RELEASE(pRowset);
//END of results.
TESTC_(pMultResults->m_pIMultResults->GetResult(NULL,
rgFlag[5], rgIID[5], &pMultResults->m_cRowsGetResultAffected,
(IUnknown **)&pRowset), DB_S_NORESULT)
SAFE_RELEASE(pRowset);
*/
CLEANUP:
if (pMultResults)
{
pMultResults->ReleaseIMultipleResults();
delete pMultResults;
}
SAFE_RELEASE(pRowset);
SetRowsetPropertyDefault(DBPROP_IRow);
TRETURN
}
// }} TCW_VAR_PROTOTYPE_END
// {{ TCW_VAR_PROTOTYPE(61)
//*-----------------------------------------------------------------------
// @mfunc DBPROP_IRow (true) : Set as required and flag = ROWSET
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCGetResult_Rowset::Variation_61()
{
// TO DO: Add your own code here
return TEST_SKIPPED;
}
// }} TCW_VAR_PROTOTYPE_END
// {{ TCW_TERMINATE_METHOD
//--------------------------------------------------------------------
// @mfunc TestCase Termination Routine
//
// @rdesc TRUE or FALSE
//
BOOL TCGetResult_Rowset::Terminate()
{
// {{ TCW_TERM_BASECLASS_CHECK2
return(CTestBase::Terminate());
} // }}
// }}
// }}
// {{ TCW_TC_PROTOTYPE(TCTxn)
//*-----------------------------------------------------------------------
//| Test Case: TCTxn - Tests Rowset behavior upon ending aTransaction
//| Created: 10/01/96
//*-----------------------------------------------------------------------
//--------------------------------------------------------------------
// @mfunc TestCase Initialization Routine
//
// @rdesc TRUE or FALSE
//
BOOL TCTxn::Init()
{
ICommandProperties * pICmdProps = NULL;
ULONG ulIndex = 0;
m_hr = E_FAIL;
m_fCommitPreserve = FALSE;
m_fAbortPreserve = FALSE;
// {{ TCW_INIT_BASECLASS_CHECK
if(CTestBase::Init() == TEST_PASS)
// }}
{
if (FAILED(m_hr=m_pICommandText->QueryInterface(IID_ICommandProperties,
(void **)&pICmdProps)))
goto END;
if (GetProperty(DBPROP_ABORTPRESERVE, DBPROPSET_ROWSET, pICmdProps))
m_fAbortPreserve = TRUE;
if (GetProperty(DBPROP_COMMITPRESERVE, DBPROPSET_ROWSET, pICmdProps))
m_fCommitPreserve = TRUE;
}
END:
// Release ICommandProperties pointer
if (pICmdProps)
pICmdProps->Release();
if (SUCCEEDED(m_hr))
return TRUE;
else
return FALSE;
}
//*-----------------------------------------------------------------------
// @mfunc TestTxn
// Tests commit/abort preservation with respect to IAccessor on rowsets
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCTxn::TestTxn(ETXN eTxn, BOOL fRetaining)
{
BOOL fSuccess = FALSE;
ITransactionLocal * pITxnLocal = NULL;
IRowset * pIRowset = NULL;
IRowset * pIRowset2 = NULL;
BOOL fResults = FALSE;
CMultResults * pMultResults = NULL;
ESQLSTMT rgeSQLStmts[] = {
ESELECT,
EINSERT,
ESELECT
};
ULONG ceSQLStmts = sizeof(rgeSQLStmts) / sizeof(ESQLSTMT);
DBCOUNTITEM cRowsObtained = 0;
HROW hRow;
HROW * phRow = &hRow;
//If we don't support Transactions, we won't test them
if (!CHECK((m_pThisTestModule->m_pIUnknown2)->QueryInterface(IID_ITransactionLocal,
(void **)&pITxnLocal),
S_OK))
return TEST_PASS;
if (!CHECK(pITxnLocal->StartTransaction(ISOLATIONLEVEL_READCOMMITTED,
0,
NULL,
NULL),
S_OK))
goto CLEANUP;
//Get an IMultipleResults interface
if (CHECK(SetUpGetResult(&pMultResults,
ceSQLStmts,
rgeSQLStmts),
S_OK))
{
if (CHECK(pMultResults->m_pIMultResults->GetResult(NULL,
0,
IID_IRowset,
&pMultResults->m_cRowsGetResultAffected,
(IUnknown **)&pIRowset), S_OK))
{
if (eTxn == ETXN_COMMIT)
{
//Commit the transaction, with retention as specified
if (!CHECK(pITxnLocal->Commit(fRetaining, 0, 0), S_OK))
goto CLEANUP;
}
else
{
//Abort the transaction, with retention as specified
if(!CHECK(pITxnLocal->Abort(NULL, fRetaining, FALSE), S_OK))
goto CLEANUP;
}
//Make sure everything still works after commit or abort
if((eTxn == ETXN_COMMIT && m_fCommitPreserve) ||
(eTxn == ETXN_ABORT && m_fAbortPreserve))
{
//Make sure our present rowset results worsk
if (CHECK(pMultResults->VerifySelectRowset(IID_IRowset, pIRowset, TRUE), S_OK))
{
//Mark that we've released this interface
pIRowset->Release();
pIRowset = NULL;
//Also process the rest of the results
if (CHECK(pMultResults->ProcessAllResults(1, IID_IMultipleResults, NULL), S_OK))
fResults = TRUE;
}
}
//We should be zombied so check that we behave that way
else
{
if (CHECK(pMultResults->m_pIMultResults->GetResult(NULL,
0,
IID_IRowset,
&pMultResults->m_cRowsGetResultAffected,
(IUnknown **)&pIRowset2),
E_UNEXPECTED))
{
COMPARE(pIRowset2, NULL);
if (CHECK(pIRowset->GetNextRows(NULL,
0,
1,
&cRowsObtained,
(HROW **)&phRow),
E_UNEXPECTED))
fResults = TRUE;
}
}
}
}
CLEANUP:
//Return code of Commit/Abort will vary depending on whether
//or not we have an open txn, so adjust accordingly
if (pITxnLocal)
{
if (fRetaining)
CHECK(pITxnLocal->Commit(FALSE, 0, 0), S_OK);
else
CHECK(pITxnLocal->Commit(FALSE, 0, 0),XACT_E_NOTRANSACTION);
pITxnLocal->Release();
}
if (pIRowset)
pIRowset->Release();
if (pIRowset2)
pIRowset2->Release();
if (pMultResults)
{
pMultResults->ReleaseIMultipleResults();
delete pMultResults;
}
if (fResults)
return TEST_PASS;
else
return TEST_FAIL;
}
// {{ TCW_VAR_PROTOTYPE(1)
//*-----------------------------------------------------------------------
// @mfunc Commit Retaining
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCTxn::Variation_1()
{
return TestTxn(ETXN_COMMIT, TRUE);
}
// }}
// {{ TCW_VAR_PROTOTYPE(2)
//*-----------------------------------------------------------------------
// @mfunc Commit NonRetaining
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCTxn::Variation_2()
{
return TestTxn(ETXN_COMMIT, FALSE);
}
// }}
// {{ TCW_VAR_PROTOTYPE(3)
//*-----------------------------------------------------------------------
// @mfunc Abort Retaining
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCTxn::Variation_3()
{
return TestTxn(ETXN_ABORT, TRUE);
}
// }}
// {{ TCW_VAR_PROTOTYPE(4)
//*-----------------------------------------------------------------------
// @mfunc Abort NonRetaining
//
// @rdesc TEST_PASS or TEST_FAIL
//
int TCTxn::Variation_4()
{
return TestTxn(ETXN_ABORT, FALSE);
}
// }}
// {{ TCW_TERMINATE_METHOD
//--------------------------------------------------------------------
// @mfunc TestCase Termination Routine
//
// @rdesc TRUE or FALSE
//
BOOL TCTxn::Terminate()
{
// {{ TCW_TERM_BASECLASS_CHECK2
return(CTestBase::Terminate());
} // }}
// }}
// }}