777 lines
21 KiB
C++
777 lines
21 KiB
C++
//---------------------------------------------------------------------
|
|
// This file is part of the Microsoft .NET Framework SDK Code Samples.
|
|
//
|
|
// Copyright (C) Microsoft Corporation. All rights reserved.
|
|
//
|
|
//This source code is intended only as a supplement to Microsoft
|
|
//Development Tools and/or on-line documentation. See these other
|
|
//materials for detailed information regarding Microsoft code samples.
|
|
//
|
|
//THIS CODE AND INFORMATION ARE PROVIDED AS IS WITHOUT WARRANTY OF ANY
|
|
//KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
|
|
//IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
|
|
//PARTICULAR PURPOSE.
|
|
//---------------------------------------------------------------------
|
|
|
|
#define DBINITCONSTANTS
|
|
|
|
#include "stdio.h"
|
|
#include "string.h"
|
|
#include "sqloledb.h"
|
|
#include "xolehlp.h"
|
|
#include "time.h"
|
|
#include "transact.h"
|
|
|
|
// Process 5 rows at a time.
|
|
#define NUMROWS_CHUNK 5
|
|
|
|
IMalloc* g_pIMalloc;
|
|
|
|
BOOL Abort = FALSE; //if FALSE transaction will be comitted. If TRUE transaction will be aborted.
|
|
|
|
DWORD serverNameLen = MAX_COMPUTERNAME_LENGTH+1;
|
|
WCHAR serverName[MAX_COMPUTERNAME_LENGTH+1];
|
|
WCHAR* dbName = L"pubs";
|
|
WCHAR* sqlCommand = L"INSERT jobs VALUES ('Test', 10, 100) SELECT COUNT(*) FROM jobs";
|
|
|
|
void ParseCommandLine(int argc, WCHAR** argv)
|
|
{
|
|
|
|
BOOL UseLocalServer = TRUE;
|
|
|
|
//Parse command line arguments
|
|
for ( int i = 1; i < argc; i++ )
|
|
{
|
|
if ( 0 == _wcsnicmp( argv[i], L"-server",7))
|
|
{
|
|
wcsncpy_s(serverName, argv[i+1], MAX_COMPUTERNAME_LENGTH);
|
|
serverName[MAX_COMPUTERNAME_LENGTH] = '\0';
|
|
UseLocalServer = FALSE;
|
|
i++;
|
|
}
|
|
else if ( 0 == _wcsnicmp( argv[i], L"-abort",6))
|
|
{
|
|
Abort = TRUE;
|
|
}
|
|
else if ( 0 == _wcsnicmp( argv[i], L"-help",5))
|
|
{
|
|
wprintf(L"\n\nUsage: %s [-server <servername>] [-abort] \n\n",argv[0]);
|
|
wprintf(L" -server <servername>\n");
|
|
wprintf(L" SQL server to connect to. Default is the local machine.\n\n");
|
|
wprintf(L" -abort\n");
|
|
wprintf(L" Aborts the transaction at the end. Otherwise by default the\n");
|
|
wprintf(L" transaction will be comitted.\n\n");
|
|
wprintf(L" NOTE: All command line parameters are case sensitive.\n\n");
|
|
exit (1);
|
|
}
|
|
else
|
|
{
|
|
wprintf(L"\n\nInvalid parameters.\nType '%s -help' for help.\n\n", argv[0]);
|
|
exit(1);
|
|
}
|
|
|
|
}
|
|
|
|
if (UseLocalServer && !GetComputerNameW(serverName, &serverNameLen))
|
|
{
|
|
wprintf(L"GetComputerNameW() returned 0x%x\n", GetLastError());
|
|
exit(1);
|
|
}
|
|
|
|
//Display the configuration information
|
|
wprintf(L"\n---------------------------------\n");
|
|
wprintf(L"(Type '%s -help' for usage)\n\n", argv[0]);
|
|
wprintf(L"CONFIGURATION\n");
|
|
if (Abort == TRUE)
|
|
wprintf(L"Transaction will be aborted.\n");
|
|
else
|
|
wprintf(L"Transaction will be comitted.\n");
|
|
wprintf(L"serverName = %s\n", serverName);
|
|
wprintf(L"dbName = %s\n", dbName);
|
|
wprintf(L"sqlCommand = %s\n", sqlCommand);
|
|
wprintf(L"---------------------------------\n\n");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
HRESULT InitializeDatabase(const WCHAR* srvName, const WCHAR* databaseName, IDBInitialize** ppIDBInitialize)
|
|
{
|
|
HRESULT hr = E_FAIL;
|
|
IDBInitialize* pIDBInitialize = NULL;
|
|
IDBProperties* pIDBProperties = NULL;
|
|
DBPROP InitProperties[4];
|
|
DBPROPSET rgInitPropSet[1];
|
|
|
|
// Create an instance of the data source object.
|
|
hr = CoCreateInstance(CLSID_SQLOLEDB, NULL, CLSCTX_INPROC_SERVER, IID_IDBInitialize, (void**)&pIDBInitialize);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
//Initialize the property values needed to establish the connection.
|
|
for (int i = 0; i < 4; i++)
|
|
{
|
|
VariantInit(&InitProperties[i].vValue);
|
|
}
|
|
|
|
//Server name.
|
|
InitProperties[0].dwPropertyID = DBPROP_INIT_DATASOURCE;
|
|
InitProperties[0].vValue.vt = VT_BSTR;
|
|
InitProperties[0].vValue.bstrVal = SysAllocString(srvName);
|
|
InitProperties[0].dwOptions = DBPROPOPTIONS_REQUIRED;
|
|
InitProperties[0].colid = DB_NULLID;
|
|
|
|
//Database.
|
|
InitProperties[1].dwPropertyID = DBPROP_INIT_CATALOG;
|
|
InitProperties[1].vValue.vt = VT_BSTR;
|
|
InitProperties[1].vValue.bstrVal = SysAllocString(databaseName);
|
|
InitProperties[1].dwOptions = DBPROPOPTIONS_REQUIRED;
|
|
InitProperties[1].colid = DB_NULLID;
|
|
|
|
//Using Windows Authentication.
|
|
InitProperties[2].dwPropertyID = DBPROP_AUTH_INTEGRATED;
|
|
InitProperties[2].vValue.vt = VT_BSTR;
|
|
InitProperties[2].vValue.bstrVal = SysAllocString(L"SSPI");
|
|
InitProperties[2].dwOptions = DBPROPOPTIONS_REQUIRED;
|
|
InitProperties[2].colid = DB_NULLID;
|
|
|
|
// Construct the DBPROPSET structure(rgInitPropSet). The DBPROPSET structure is used to pass an array of DBPROP
|
|
// structures (InitProperties) to the SetProperties method.
|
|
rgInitPropSet[0].guidPropertySet = DBPROPSET_DBINIT;
|
|
rgInitPropSet[0].cProperties = 4;
|
|
rgInitPropSet[0].rgProperties = InitProperties;
|
|
|
|
//Set initialization properties.
|
|
hr = pIDBInitialize->QueryInterface(IID_IDBProperties, (void **)&pIDBProperties);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = pIDBProperties->SetProperties(1, rgInitPropSet);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
//Now establish the connection to the data source.
|
|
hr = pIDBInitialize->Initialize();
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
*ppIDBInitialize = pIDBInitialize;
|
|
}
|
|
else
|
|
{
|
|
wprintf(L"pIDBProperties->Initialize() returned hr=0x%x\n", hr);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
wprintf(L"pIDBProperties->SetProperties() returned hr=0x%x\n", hr);
|
|
}
|
|
pIDBProperties->Release();
|
|
}
|
|
else
|
|
{
|
|
wprintf(L"QueryInterface(IID_IDBProperties) returned hr=0x%x\n", hr);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
wprintf(L"CoCreateInstance(CLSID_SQLOLEDB, IID_IDBInitialize) returned hr=0x%x\n", hr);
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
|
|
//********************************************************************
|
|
HRESULT GetDBCreateSession(IDBInitialize* pIDBInitialize, IDBCreateSession** ppIDBCreateSession)
|
|
{
|
|
HRESULT hr = E_FAIL;
|
|
IDBCreateSession* pIDBCreateSession = NULL;
|
|
|
|
hr = pIDBInitialize->QueryInterface(IID_IDBCreateSession, (void**) &pIDBCreateSession);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
*ppIDBCreateSession = pIDBCreateSession;
|
|
}
|
|
else
|
|
{
|
|
wprintf(L"QueryInterface(IID_IDBCreateSession) returned hr=0x%x\n", hr);
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
HRESULT CreateTransaction(ITransaction** ppITransaction)
|
|
{
|
|
HRESULT hr = E_FAIL;
|
|
ITransactionDispenser* pITransactionDispenser = NULL;
|
|
ITransaction* pITransaction = NULL;
|
|
|
|
wprintf(L"Creating a transaction...\n");
|
|
//Create a transaction
|
|
hr = DtcGetTransactionManagerEx(NULL, NULL, IID_ITransactionDispenser, OLE_TM_FLAG_NONE, NULL, (void**) &pITransactionDispenser);
|
|
if (FAILED(hr))
|
|
{
|
|
wprintf(L"ERROR: Getting a transaction dispenser object failed. HR=0x%x\n", hr);
|
|
goto cleanup;
|
|
}
|
|
hr = pITransactionDispenser->BeginTransaction(NULL, ISOLATIONLEVEL_READCOMMITTED, ISOFLAG_RETAIN_BOTH, NULL, &pITransaction);
|
|
if (FAILED(hr))
|
|
{
|
|
wprintf(L"ERROR: Begin transaction call failed. HR=0x%x\n", hr);
|
|
goto cleanup;
|
|
}
|
|
|
|
*ppITransaction = pITransaction;
|
|
|
|
cleanup:
|
|
|
|
if(NULL != pITransactionDispenser)
|
|
pITransactionDispenser->Release();
|
|
|
|
return(hr);
|
|
|
|
}
|
|
|
|
HRESULT GetKernelTransactionHandle(ITransaction* pITransaction, HANDLE* ppTransactionHandle)
|
|
{
|
|
HRESULT hr = E_FAIL;
|
|
IKernelTransaction* pKernelTransaction = NULL;
|
|
HANDLE hTransactionHandle = INVALID_HANDLE_VALUE;
|
|
|
|
wprintf(L"Getting a transaction handle to use with transacted file operation...\n");
|
|
// query for IKernelTransaction interface for a handle to use with transacted file operation
|
|
hr = pITransaction->QueryInterface(IID_IKernelTransaction, (void**) &pKernelTransaction);
|
|
if (FAILED(hr))
|
|
{
|
|
wprintf(L"ERROR: QueryInterface for IKernelTransaction failed with hr=0x%x\n", hr);
|
|
goto cleanup;
|
|
}
|
|
hr = pKernelTransaction->GetHandle(&hTransactionHandle);
|
|
if (FAILED(hr))
|
|
{
|
|
wprintf(L"ERROR: GetHandle call on IKernelTransaction failed with hr=0x%x\n", hr);
|
|
goto cleanup;
|
|
}
|
|
|
|
*ppTransactionHandle = hTransactionHandle;
|
|
|
|
cleanup:
|
|
|
|
if(NULL != pKernelTransaction)
|
|
pKernelTransaction->Release();
|
|
|
|
return(hr);
|
|
|
|
}
|
|
|
|
HRESULT GetCoordinatedUniversalTime (char* uniTime)
|
|
{
|
|
HRESULT hr = E_FAIL;
|
|
|
|
struct tm newtime;
|
|
__int64 ltime;
|
|
char buf[26];
|
|
errno_t err;
|
|
|
|
//get time
|
|
_time64( <ime );
|
|
err = _gmtime64_s( &newtime, <ime );
|
|
|
|
if (err)
|
|
{
|
|
wprintf(L"ERROR: Get time function failed.");
|
|
}
|
|
|
|
// Convert to an ASCII representation
|
|
err = asctime_s(buf, _countof(buf), &newtime);
|
|
|
|
if (err)
|
|
{
|
|
wprintf(L"ERROR: Converting time to an ASCII representation failed.");
|
|
}
|
|
else
|
|
{
|
|
strcpy_s(uniTime, _countof(buf), buf);
|
|
wprintf(L"Universal time is: %S\n", buf );
|
|
hr = S_OK;
|
|
}
|
|
|
|
return(hr);
|
|
|
|
}
|
|
|
|
HRESULT TransactedFileOperation(HANDLE hTransactionHandle)
|
|
{
|
|
HRESULT hr = E_FAIL;
|
|
HANDLE hAppend = INVALID_HANDLE_VALUE;
|
|
DWORD dwBytesWritten, dwPos;
|
|
char buf[25];
|
|
|
|
wprintf(L"Open file...\n");
|
|
// Open the existing file, or if the file does not exist, create it
|
|
hAppend = CreateFileTransacted(TEXT("test.txt"), // open test.txt
|
|
FILE_APPEND_DATA, // open for writing
|
|
FILE_SHARE_READ, // allow multiple readers
|
|
NULL, // no security
|
|
OPEN_ALWAYS, // open or create
|
|
FILE_ATTRIBUTE_NORMAL, // normal file
|
|
NULL, // no attr. template
|
|
hTransactionHandle, // pass the transaction handle
|
|
NULL, // no mini version
|
|
NULL); // reserved
|
|
|
|
if (hAppend == INVALID_HANDLE_VALUE)
|
|
{
|
|
wprintf(L"ERROR: Could not open test.txt.");
|
|
goto cleanup;
|
|
}
|
|
|
|
//any operation done using hAppend handle will now be transactional
|
|
|
|
//append the current universal time to the file
|
|
hr = GetCoordinatedUniversalTime(buf);
|
|
if (FAILED(hr))
|
|
goto cleanup;
|
|
wprintf(L"Appending the time to the file...\n");
|
|
dwPos = SetFilePointer(hAppend, 0, NULL, FILE_END);
|
|
WriteFile(hAppend, buf, _countof(buf), &dwBytesWritten, NULL);
|
|
|
|
cleanup:
|
|
|
|
if(NULL != hAppend)
|
|
CloseHandle(hAppend);
|
|
|
|
return(hr);
|
|
|
|
}
|
|
|
|
HRESULT CreateTransactedCommand(IDBCreateSession* pIDBCreateSession, ITransaction* pITransaction, const WCHAR* commandText, ICommandText** ppICommandText)
|
|
{
|
|
HRESULT hr = E_FAIL;
|
|
ITransactionDispenser* pITransactionDispenser = NULL;
|
|
ITransactionJoin* pITransactionJoin = NULL;
|
|
IDBCreateCommand* pIDBCreateCommand = NULL;
|
|
ICommandText* pICommandText = NULL;
|
|
|
|
|
|
hr = pIDBCreateSession->CreateSession(NULL, IID_IDBCreateCommand, (IUnknown**) &pIDBCreateCommand);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
// Join the transaction.
|
|
hr = pIDBCreateCommand->QueryInterface(IID_ITransactionJoin, (void**) &pITransactionJoin);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = pITransactionJoin->JoinTransaction((IUnknown*) pITransaction, ISOLATIONLEVEL_READCOMMITTED, 0, NULL);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = pIDBCreateCommand->CreateCommand(NULL, IID_ICommandText, (IUnknown**) &pICommandText);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = pICommandText->SetCommandText(DBGUID_DBSQL, commandText);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
*ppICommandText = pICommandText;
|
|
}
|
|
else
|
|
{
|
|
wprintf(L"pICommandText->SetCommandText(%s) returned hr=0x%x\n", commandText, hr);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
wprintf(L"pIDBCreateCommand->CreateCommand(IID_ICommandText) returned hr=0x%x\n", hr);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
wprintf(L"pITransactionJoin->JoinTransaction(pITransaction) returned hr=0x%x\n", hr);
|
|
}
|
|
pITransactionJoin->Release();
|
|
}
|
|
else
|
|
{
|
|
wprintf(L"QueryInterface(IID_ITransactionJoin) returned hr=0x%x\n", hr);
|
|
}
|
|
pIDBCreateCommand->Release();
|
|
}
|
|
else
|
|
{
|
|
wprintf(L"pIDBCreateSession->CreateSession(IID_IDBCreateCommand) returned hr=0x%x\n", hr);
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
//********************************************************************
|
|
HRESULT ExecuteTransactedCommand(IDBCreateSession* pIDBCreateSession, const WCHAR* commandText, ITransaction* pITransaction, IMultipleResults** ppIMultipleResults)
|
|
{
|
|
HRESULT hr = E_FAIL;
|
|
DBROWCOUNT dbRowCount = 0;
|
|
IMultipleResults* pIMultipleResults = NULL;
|
|
ICommandText* pICommandText = NULL;
|
|
|
|
|
|
hr = CreateTransactedCommand(pIDBCreateSession, pITransaction, commandText, &pICommandText);
|
|
if (FAILED(hr))
|
|
{
|
|
wprintf(L"CreateTransactedCommand() returned hr=0x%x\n", hr);
|
|
goto cleanup;
|
|
}
|
|
|
|
//Execute the SQL command
|
|
wprintf(L"Executing the database query...\n");
|
|
hr = pICommandText->Execute(NULL, IID_IMultipleResults, NULL, &dbRowCount, (IUnknown**) &pIMultipleResults);
|
|
if (FAILED(hr))
|
|
{
|
|
wprintf(L"pICommandText->Execute() returned hr=0x%x\n", hr);
|
|
goto cleanup;
|
|
}
|
|
|
|
*ppIMultipleResults = pIMultipleResults;
|
|
|
|
cleanup:
|
|
|
|
if(NULL != pICommandText)
|
|
pICommandText->Release();
|
|
|
|
return hr;
|
|
|
|
}
|
|
|
|
HRESULT GetDBBindings(ULONG nCols, DBCOLUMNINFO* pColumnsInfo, DBBINDING** ppDBBindings, char** ppRowValues)
|
|
{
|
|
HRESULT hr = E_FAIL;
|
|
ULONG nCol;
|
|
ULONG cbRow = 0;
|
|
DBBINDING* pDBBindings = NULL;
|
|
char* pRowValues = NULL;
|
|
|
|
try {
|
|
|
|
pDBBindings = new DBBINDING[nCols];
|
|
if (pDBBindings != NULL)
|
|
{
|
|
for (nCol = 0; nCol < nCols; nCol++)
|
|
{
|
|
pDBBindings[nCol].iOrdinal = nCol+1;
|
|
pDBBindings[nCol].obValue = cbRow;
|
|
pDBBindings[nCol].obLength = 0;
|
|
pDBBindings[nCol].obStatus = 0;
|
|
pDBBindings[nCol].pTypeInfo = NULL;
|
|
pDBBindings[nCol].pObject = NULL;
|
|
pDBBindings[nCol].pBindExt = NULL;
|
|
pDBBindings[nCol].dwPart = DBPART_VALUE;
|
|
pDBBindings[nCol].dwMemOwner = DBMEMOWNER_CLIENTOWNED;
|
|
pDBBindings[nCol].eParamIO = DBPARAMIO_NOTPARAM;
|
|
pDBBindings[nCol].cbMaxLen = pColumnsInfo[nCol].ulColumnSize;
|
|
pDBBindings[nCol].dwFlags = 0;
|
|
pDBBindings[nCol].wType = pColumnsInfo[nCol].wType;
|
|
pDBBindings[nCol].bPrecision = pColumnsInfo[nCol].bPrecision;
|
|
pDBBindings[nCol].bScale = pColumnsInfo[nCol].bScale;
|
|
cbRow += pDBBindings[nCol].cbMaxLen;
|
|
}
|
|
|
|
if (cbRow > 0)
|
|
{
|
|
pRowValues = new char[cbRow];
|
|
if (pRowValues != NULL)
|
|
{
|
|
*ppDBBindings = pDBBindings;
|
|
*ppRowValues = pRowValues;
|
|
hr = S_OK;
|
|
}
|
|
else
|
|
{
|
|
wprintf(L"pRowValues == NULL.\n");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
wprintf(L"cbRow <= 0.\n");
|
|
}
|
|
|
|
if (hr != S_OK)
|
|
{
|
|
delete [] pDBBindings;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
wprintf(L"pDBBindings == NULL.\n");
|
|
}
|
|
|
|
}
|
|
|
|
catch (...)
|
|
{
|
|
wprintf(L"Exception occured while getting DB bindings.");
|
|
|
|
if (NULL != pDBBindings)
|
|
delete [] pDBBindings;
|
|
|
|
throw;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
void ProcessRowset(IRowset* pIRowset)
|
|
{
|
|
HRESULT hr;
|
|
ULONG nCols;
|
|
IColumnsInfo* pIColumnsInfo = NULL;
|
|
DBCOLUMNINFO* pColumnsInfo = NULL;
|
|
OLECHAR* pColumnStrings = NULL;
|
|
ULONG nCol;
|
|
ULONG cRowsObtained;
|
|
ULONG iRow;
|
|
HROW rghRows[NUMROWS_CHUNK];
|
|
HROW* pRows = &rghRows[0];
|
|
IAccessor* pIAccessor;
|
|
HACCESSOR hAccessor;
|
|
DBBINDSTATUS* pDBBindStatus = NULL;
|
|
DBBINDING* pDBBindings = NULL;
|
|
char* pRowValues;
|
|
|
|
hr = pIRowset->QueryInterface(IID_IColumnsInfo, (void**) &pIColumnsInfo);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = pIColumnsInfo->GetColumnInfo(&nCols, &pColumnsInfo, &pColumnStrings);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = GetDBBindings(nCols, pColumnsInfo, &pDBBindings, &pRowValues);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
pDBBindStatus = new DBBINDSTATUS[nCols];
|
|
if (pDBBindStatus != NULL)
|
|
{
|
|
hr = pIRowset->QueryInterface(IID_IAccessor, (void**) &pIAccessor);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = pIAccessor->CreateAccessor(DBACCESSOR_ROWDATA, nCols, pDBBindings, 0, &hAccessor, pDBBindStatus);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
// Process all the rows, NUMROWS_CHUNK rows at a time.
|
|
do
|
|
{
|
|
hr = pIRowset->GetNextRows(0, 0, NUMROWS_CHUNK, &cRowsObtained, &pRows);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
// Loop over rows obtained, getting data for each.
|
|
for (iRow=0; iRow < cRowsObtained; iRow++)
|
|
{
|
|
pIRowset->GetData(rghRows[iRow], hAccessor, pRowValues);
|
|
for (nCol = 0; nCol < nCols; nCol++)
|
|
{
|
|
wprintf(L"COUNT(jobs)=%i\n", pRowValues[pDBBindings[nCol].obValue]);
|
|
}
|
|
}
|
|
pIRowset->ReleaseRows(cRowsObtained, rghRows, NULL, NULL, NULL);
|
|
}
|
|
else
|
|
{
|
|
wprintf(L"pIRowset->GetNextRows() returned hr=0x%x\n", hr);
|
|
}
|
|
}
|
|
while (cRowsObtained > 0);
|
|
pIAccessor->ReleaseAccessor(hAccessor, NULL);
|
|
}
|
|
else
|
|
{
|
|
wprintf(L"pIAccessor->CreateAccessor() returned hr=0x%x\n", hr);
|
|
}
|
|
pIAccessor->Release();
|
|
}
|
|
else
|
|
{
|
|
wprintf(L"pIRowset->QueryInterface(IID_IAccessor) returned hr=0x%x\n", hr);
|
|
}
|
|
delete [] pDBBindStatus;
|
|
}
|
|
else
|
|
{
|
|
wprintf(L"pDBBindStatus == NULL.\n");
|
|
hr = E_FAIL;
|
|
}
|
|
delete [] pDBBindings;
|
|
delete [] pRowValues;
|
|
}
|
|
else
|
|
{
|
|
wprintf(L"GetDBBindings() returned hr=0x%x\n", hr);
|
|
}
|
|
g_pIMalloc->Free(pColumnsInfo);
|
|
g_pIMalloc->Free(pColumnStrings);
|
|
}
|
|
else
|
|
{
|
|
wprintf(L"GetColumnInfo() returned hr=0x%x\n", hr);
|
|
}
|
|
pIColumnsInfo->Release();
|
|
}
|
|
else
|
|
{
|
|
wprintf(L"pIRowset->QueryInterface(IID_IColumnsInfo) returned hr=0x%x\n", hr);
|
|
}
|
|
return;
|
|
}
|
|
|
|
HRESULT DisplaySQLRowSetCount (IMultipleResults* pIMultipleResults)
|
|
{
|
|
HRESULT hr = E_FAIL;
|
|
DBROWCOUNT dbRowCount = 0;
|
|
IRowset* pIRowset = NULL;
|
|
|
|
|
|
//Display the SQL data before the transaction commits
|
|
hr = pIMultipleResults->GetResult(NULL, DBRESULTFLAG_DEFAULT, IID_IRowset, &dbRowCount, (IUnknown**) &pIRowset);
|
|
if (hr == S_OK)
|
|
{
|
|
// Because the SQL statement alters the data it is reading and the isolation level is read committed,
|
|
// the data is not available yet.
|
|
wprintf(L"SQL rowset: ");
|
|
if (pIRowset != NULL)
|
|
{
|
|
ProcessRowset(pIRowset);
|
|
pIRowset->Release();
|
|
}
|
|
else
|
|
{
|
|
wprintf(L"No IRowset yet to process.\n");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
wprintf(L"pIMultipleResults->GetResult failed. HR=0x%x\n", hr);
|
|
}
|
|
|
|
return(hr);
|
|
}
|
|
|
|
HRESULT CommitOrAbortTransaction(ITransaction* pITransaction, BOOL AbortTransaction)
|
|
{
|
|
HRESULT hr = E_FAIL;
|
|
|
|
if (AbortTransaction == FALSE)
|
|
{
|
|
// Commit the transaction
|
|
wprintf(L"Comitting transaction...\n");
|
|
hr = pITransaction->Commit(FALSE, XACTTC_SYNC_PHASEONE, 0);
|
|
if (FAILED(hr))
|
|
{
|
|
wprintf(L"ERROR: Commit operation failed. HR=0x%x\n", hr);
|
|
}
|
|
else
|
|
{
|
|
wprintf(L"\nCommit operation succeeded.\n\n");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//abort the transaction
|
|
wprintf(L"Aborting transaction...\n");
|
|
hr = pITransaction->Abort(NULL, //don't provide a reason for abort
|
|
FALSE, //must be FALSE
|
|
FALSE); //abort synchronous
|
|
if (FAILED(hr))
|
|
{
|
|
wprintf(L"ERROR: Abort operation failed. HR=0x%x\n", hr);
|
|
}
|
|
else
|
|
{
|
|
wprintf(L"\nAbort operation succeeded.\n\n");
|
|
}
|
|
}
|
|
|
|
return(hr);
|
|
|
|
}
|
|
|
|
//********************************************************************
|
|
int __cdecl wmain(int argc, WCHAR* argv[])
|
|
{
|
|
HRESULT hr = S_OK;
|
|
IDBCreateSession* pIDBCreateSession = NULL;
|
|
IDBInitialize* pIDBInitialize = NULL;
|
|
IMultipleResults* pIMultipleResults = NULL;
|
|
ITransaction* pITransaction = NULL;
|
|
HANDLE hTransactionHandle = INVALID_HANDLE_VALUE;
|
|
|
|
|
|
ParseCommandLine(argc, argv);
|
|
|
|
//Initialize COM
|
|
hr = CoInitialize(NULL);
|
|
if (FAILED(hr))
|
|
{
|
|
wprintf(L"CoInitialize(NULL) returned hr=0x%x\n", hr);
|
|
goto cleanup;
|
|
}
|
|
hr = CoGetMalloc(MEMCTX_TASK, &g_pIMalloc);
|
|
if (FAILED(hr))
|
|
{
|
|
wprintf(L"CoGetMalloc(MEMCTX_TASK) returned hr=0x%x\n", hr);
|
|
goto cleanup;
|
|
}
|
|
|
|
//Initialize the database
|
|
wprintf(L"Initializing the database...\n");
|
|
hr = InitializeDatabase(serverName, dbName, &pIDBInitialize);
|
|
if (FAILED(hr)) goto cleanup;
|
|
|
|
//create a database session
|
|
hr = GetDBCreateSession(pIDBInitialize, &pIDBCreateSession);
|
|
if (FAILED(hr)) goto cleanup;
|
|
|
|
// Get a pointer to a new transaction
|
|
hr = CreateTransaction(&pITransaction);
|
|
if (FAILED(hr)) goto cleanup;
|
|
|
|
// Get a transaction handle to use with transacted file operation
|
|
hr = GetKernelTransactionHandle(pITransaction, &hTransactionHandle);
|
|
|
|
// Do transacted file operations
|
|
if (SUCCEEDED(hr))
|
|
hr = TransactedFileOperation(hTransactionHandle);
|
|
|
|
// Do transacted database operations
|
|
if (SUCCEEDED(hr))
|
|
hr = ExecuteTransactedCommand(pIDBCreateSession, sqlCommand, pITransaction, &pIMultipleResults);
|
|
|
|
// If anything after the creation of ITransaction failed, abort the transaction
|
|
if (FAILED(hr))
|
|
{ wprintf(L"Due to errors, transaction will be aborted...\n");
|
|
//force transaction to abort
|
|
hr = CommitOrAbortTransaction(pITransaction, TRUE);
|
|
if (FAILED(hr)) goto cleanup;
|
|
}
|
|
|
|
//Display the row count of the SQL table before commit or abort
|
|
DisplaySQLRowSetCount(pIMultipleResults);
|
|
|
|
//commit or abort the transaction depending on the '-abort' command line parameter
|
|
hr = CommitOrAbortTransaction(pITransaction, Abort);
|
|
if (FAILED(hr)) goto cleanup;
|
|
|
|
//Display the row count of the SQL table after the commit or abort
|
|
DisplaySQLRowSetCount(pIMultipleResults);
|
|
|
|
|
|
cleanup:
|
|
|
|
if (NULL != g_pIMalloc)
|
|
g_pIMalloc->Release();
|
|
|
|
if(NULL != hTransactionHandle)
|
|
CloseHandle(hTransactionHandle);
|
|
|
|
if(NULL != pIMultipleResults)
|
|
pIMultipleResults->Release();
|
|
if(NULL != pITransaction)
|
|
pITransaction->Release();
|
|
if (NULL != pIDBCreateSession)
|
|
pIDBCreateSession->Release();
|
|
if (NULL != pIDBInitialize)
|
|
pIDBInitialize->Release();
|
|
|
|
CoUninitialize();
|
|
|
|
return (hr);
|
|
}
|