27 namespace relpipe { |
27 namespace relpipe { |
28 namespace tr { |
28 namespace tr { |
29 namespace sql { |
29 namespace sql { |
30 |
30 |
31 Connection::Connection(void* db) : connection(db) { |
31 Connection::Connection(void* db) : connection(db) { |
32 // TODO: transaction control |
32 setAutoCommit(false); |
33 } |
33 } |
34 |
34 |
35 Connection::~Connection() { |
35 Connection::~Connection() { |
|
36 // If an exception was thrown somewhere, there might be a transaction in progress, so we will cancel this transaction. |
|
37 // If there was no exception, commit() has already been called and this rollback() will not affect any (desired) transaction. |
|
38 // Without this rollback(), SQLDisconnect() will fail and then will fail also freeHandle() which will throw exception. |
|
39 // And throwing exception while throwing exception will lead to a catastrophic failure: SIGABRT, core dump. |
|
40 rollback(); |
36 SQLRETURN result = SQLDisconnect(connection); |
41 SQLRETURN result = SQLDisconnect(connection); |
37 // TODO: log warning if disconnection failed? |
|
38 OdbcCommon::freeHandle(SQL_HANDLE_DBC, connection); |
42 OdbcCommon::freeHandle(SQL_HANDLE_DBC, connection); |
39 } |
43 } |
40 |
44 |
41 PreparedStatement* Connection::prepareStatement(relpipe::reader::string_t sql) { |
45 PreparedStatement* Connection::prepareStatement(relpipe::reader::string_t sql) { |
42 SQLHSTMT statement = OdbcCommon::allocateHandle(SQL_HANDLE_STMT, connection); |
46 SQLHSTMT statement = OdbcCommon::allocateHandle(SQL_HANDLE_STMT, connection); |
44 if (OdbcCommon::isNotSuccessful(result)) throw SqlException(L"Unable to prepare statement", result, SQL_HANDLE_STMT, statement, true); |
48 if (OdbcCommon::isNotSuccessful(result)) throw SqlException(L"Unable to prepare statement", result, SQL_HANDLE_STMT, statement, true); |
45 return new PreparedStatement(statement); |
49 return new PreparedStatement(statement); |
46 } |
50 } |
47 |
51 |
48 bool Connection::getAutoCommit() { |
52 bool Connection::getAutoCommit() { |
49 // TODO: transaction control |
53 SQLULEN autoCommit = SQL_AUTOCOMMIT_DEFAULT; |
50 return false; |
54 SQLRETURN result = SQLGetConnectOption(connection, SQL_AUTOCOMMIT, &autoCommit); |
|
55 if (OdbcCommon::isNotSuccessful(result)) throw SqlException(L"Unable to get auto-commit status", result, SQL_HANDLE_DBC, connection); |
|
56 |
|
57 if (autoCommit == SQL_AUTOCOMMIT_ON) return true; |
|
58 else if (autoCommit == SQL_AUTOCOMMIT_OFF) return false; |
|
59 else throw SqlException(L"Unexpected value of auto-commit status"); |
51 } |
60 } |
52 |
61 |
53 void Connection::setAutoCommit(bool autoCommit) { |
62 void Connection::setAutoCommit(bool autoCommit) { |
54 // TODO: transaction control |
63 SQLRETURN result = SQLSetConnectOption(connection, SQL_AUTOCOMMIT, autoCommit ? SQL_AUTOCOMMIT_ON : SQL_AUTOCOMMIT_OFF); |
|
64 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); |
55 } |
65 } |
56 |
66 |
57 void Connection::commit() { |
67 void Connection::commit() { |
58 SQLRETURN result = SQLEndTran(SQL_HANDLE_DBC, connection, SQL_COMMIT); |
68 SQLRETURN result = SQLEndTran(SQL_HANDLE_DBC, connection, SQL_COMMIT); |
59 if (OdbcCommon::isNotSuccessful(result)) throw SqlException(L"Unable to COMMIT: " + std::to_wstring(result)); |
69 if (OdbcCommon::isNotSuccessful(result)) throw SqlException(L"Unable to COMMIT: " + std::to_wstring(result)); |