transaction control: disable auto-commit, run all statements in a single transaction, do rollback on exception v_0
authorFrantišek Kučera <franta-hg@frantovo.cz>
Thu, 04 Jun 2020 00:03:37 +0200
branchv_0
changeset 46 85e6dc1853ee
parent 45 225e294ad1db
child 47 428c278af4be
transaction control: disable auto-commit, run all statements in a single transaction, do rollback on exception
src/Connection.cpp
--- 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() {