transaction control: disable auto-commit, run all statements in a single transaction, do rollback on exception
--- a/src/Connection.cpp Wed Jun 03 17:22:22 2020 +0200
+++ b/src/Connection.cpp Thu Jun 04 00:03:37 2020 +0200
@@ -29,12 +29,16 @@
namespace sql {
Connection::Connection(void* db) : connection(db) {
- // TODO: transaction control
+ setAutoCommit(false);
}
Connection::~Connection() {
+ // If an exception was thrown somewhere, there might be a transaction in progress, so we will cancel this transaction.
+ // If there was no exception, commit() has already been called and this rollback() will not affect any (desired) transaction.
+ // Without this rollback(), SQLDisconnect() will fail and then will fail also freeHandle() which will throw exception.
+ // And throwing exception while throwing exception will lead to a catastrophic failure: SIGABRT, core dump.
+ rollback();
SQLRETURN result = SQLDisconnect(connection);
- // TODO: log warning if disconnection failed?
OdbcCommon::freeHandle(SQL_HANDLE_DBC, connection);
}
@@ -46,12 +50,18 @@
}
bool Connection::getAutoCommit() {
- // TODO: transaction control
- return false;
+ SQLULEN autoCommit = SQL_AUTOCOMMIT_DEFAULT;
+ SQLRETURN result = SQLGetConnectOption(connection, SQL_AUTOCOMMIT, &autoCommit);
+ if (OdbcCommon::isNotSuccessful(result)) throw SqlException(L"Unable to get auto-commit status", result, SQL_HANDLE_DBC, connection);
+
+ if (autoCommit == SQL_AUTOCOMMIT_ON) return true;
+ else if (autoCommit == SQL_AUTOCOMMIT_OFF) return false;
+ else throw SqlException(L"Unexpected value of auto-commit status");
}
void Connection::setAutoCommit(bool autoCommit) {
- // TODO: transaction control
+ SQLRETURN result = SQLSetConnectOption(connection, SQL_AUTOCOMMIT, autoCommit ? SQL_AUTOCOMMIT_ON : SQL_AUTOCOMMIT_OFF);
+ if (OdbcCommon::isNotSuccessful(result)) throw SqlException(std::wstring(L"Unable to set auto-commit to ") + (autoCommit ? L"enabled" : L"disabled"), result, SQL_HANDLE_DBC, connection);
}
void Connection::commit() {