bool TestXaRunner(HDBC hdbc, const char* connString, TestType testType, int timeout = 0) { SQLHSTMT hstmt; SQLRETURN rc = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt); XaTestRunner::CheckRC(rc, "TestXaRunner::Alloc statement", hdbc, SQL_HANDLE_DBC); const int ROWS_TO_TEST = 10; int rowCount = 0; bool result = false; if (SQL_SUCCEEDED(rc)) { std::string tableName; auto testRunner = std::make_shared(hdbc); testRunner->GetUniqueName(tableName); bool isTableCreated = false; RETCODE xaStatus = SQL_ERROR; bool isTimeoutTest = false; XID xid; XaTestRunner::GetUniqueXid(xid); do { if (!(isTableCreated = testRunner->CreateTable(tableName))) { std::cout << "TestXaRunner::Failed to create table " << tableName.c_str() << std::endl; break; } if (timeout > 0) { testRunner->SetTimeout(timeout); isTimeoutTest = true; } rc = testRunner->Start(xid, TMNOFLAGS, xaStatus); if (SQL_SUCCEEDED(xaStatus)) { rc = testRunner->ExecuteInsertSequence(tableName, ROWS_TO_TEST, hstmt); XaTestRunner::CheckRC(rc, "TestXaRunner::ExecuteInsertSequence", hstmt, SQL_HANDLE_STMT); if (isTimeoutTest) { auto timeToSleep = timeout + 5; std::cout << "Sleep for " << timeToSleep << " seconds" << std::endl; std::this_thread::sleep_for(std::chrono::seconds(timeToSleep)); } rc = testRunner->End(xid, TMSUCCESS, xaStatus); if (xaStatus < 0) { std::cout << "TestXaRunner::XA End failed status=" << xaStatus << std::endl; break; } switch (testType) { case TestType::Commit: rc = testRunner->Prepare(xid, xaStatus); if (xaStatus < 0) { std::cout << "TestXaRunner::XA Prepare failed status=" << xaStatus << std::endl; } else { rc = testRunner->Commit(xid, false, xaStatus); if (xaStatus < 0) { std::cout << "TestXaRunner::XA Commit failed status=" << xaStatus << std::endl; } } break; case TestType::Commit1Phase: rc = testRunner->Commit(xid, true, xaStatus); if (xaStatus < 0) { std::cout << "TestXaRunner::XA Commit one phase failed status=" << xaStatus << std::endl; } break; case TestType::Rollback: rc = testRunner->Rollback(xid, xaStatus); if (xaStatus < 0) { std::cout << "TestXaRunner::XA Rollback failed status=" << xaStatus << std::endl; } break; case TestType::Recover: break; default: break; } } else { std::cout << "TestXaRunner::XA Start failed status=" << xaStatus << std::endl; } } while (false); if (isTimeoutTest) { result = xaStatus == XAER_NOTA; std::cout << "TestXaRunner::TimeoutTest" " xaStatus=" << xaStatus << " test " << (result ? "Succeeded" : "Failed") << std::endl; } else { auto isCommit = testType == TestType::Commit || testType == TestType::Commit1Phase; rc = GetRowCount(hstmt, tableName, rowCount); result = (rowCount == (isCommit ? ROWS_TO_TEST : 0)) && SQL_SUCCEEDED(xaStatus); std::cout << "TestXaRunner::" << (isCommit ? "Commit" : "Rollback") << " rowCount=" << rowCount << " xaStatus=" << xaStatus << " test " << (result ? "Succeeded" : "Failed") << std::endl; } if (isTableCreated) { testRunner->DropTable(tableName); } rc = SQLFreeHandle(SQL_HANDLE_STMT, hstmt); rc = SQLDisconnect(hdbc); } return result; } bool TestCommit(HDBC hdbc, const char* connectionString) { return TestXaRunner(hdbc, connectionString, TestType::Commit); } int main(int argc, char** argv) { const char* pConnStr = ""; if (argc < 2) { std::cout << "ERROR: Connection string is not specified" << std::endl; return 0; } else { pConnStr = argv[1]; std::cout << "Connection string: " << pConnStr << std::endl; } SQLHENV henv = NULL; SQLHDBC hdbc = NULL; std::string connString = pConnStr; SQLRETURN rc; rc = SQLAllocHandle(SQL_HANDLE_ENV, NULL, &henv); XaTestRunner::CheckRC(rc, "Allocating environment", NULL, 0); rc = SQLSetEnvAttr(henv, SQL_ATTR_ODBC_VERSION, (SQLPOINTER)SQL_OV_ODBC3, 0); rc = SQLAllocHandle(SQL_HANDLE_DBC, henv, &hdbc); XaTestRunner::CheckRC(rc, "Allocating connection", henv, SQL_HANDLE_ENV); bool result; rc = SQLDriverConnect(hdbc, NULL, (SQLCHAR*)pConnStr, SQL_NTS, NULL, 0, NULL, SQL_DRIVER_NOPROMPT); XaTestRunner::CheckRC(rc, "TestXaRunner::Connecting", hdbc, SQL_HANDLE_DBC); if (!SQL_SUCCEEDED(rc)) { return false; } for (int i = 0; i < 50; i++) { result = TestCommit(hdbc, pConnStr); std::this_thread::sleep_for(std::chrono::seconds(1)); } SQLFreeHandle(SQL_HANDLE_DBC, hdbc); SQLFreeHandle(SQL_HANDLE_ENV, henv); return 0; }