1212// This class wraps low-level ODBC operations like connect/disconnect,
1313// transaction control, and autocommit configuration.
1414// -------------------------------------------------------------------------------------------------
15- Connection::Connection (const std::wstring& conn_str, bool autocommit) : _conn_str(conn_str) , _autocommit(autocommit) {}
15+ Connection::Connection (const std::wstring& conn_str, bool autocommit)
16+ : _conn_str(conn_str) , _autocommit(autocommit) {}
1617
1718Connection::~Connection () {
18- close (); // Ensure the connection is closed when the object is destroyed.
19+ close (); // Ensure the connection is closed when the object is destroyed.
1920}
2021
2122SQLRETURN Connection::connect () {
22- SQLHANDLE env = nullptr ;
23- SQLHANDLE dbc = nullptr ;
24-
25- LOG (" Allocate SQL Handle" );
26- if (!SQLAllocHandle_ptr) {
27- LOG (" Function pointer not initialized. Loading the driver." );
28- DriverLoader::getInstance ().loadDriver ();
29- }
30- SQLRETURN ret = SQLAllocHandle_ptr (SQL_HANDLE_ENV, SQL_NULL_HANDLE, &env);
31- if (!SQL_SUCCEEDED (ret)) {
32- LOG (" Failed to allocate environment handle" );
33- throw std::runtime_error (" Failed to allocate environment handle" );
34- }
35- _env_handle = std::make_shared<SqlHandle>(SQL_HANDLE_ENV, env);
36-
37- ret = SQLSetEnvAttr_ptr (env, SQL_ATTR_ODBC_VERSION, (void *)SQL_OV_ODBC3_80, 0 );
38- if (!SQL_SUCCEEDED (ret)) {
39- LOG (" Failed to set environment attribute" );
40- throw std::runtime_error (" Failed to set environment attribute" );
41- }
23+ allocDbcHandle ();
24+ return connectToDb ();
25+ }
4226
27+ // Allocates DBC handle
28+ void Connection::allocDbcHandle () {
29+ SQLHANDLE dbc = nullptr ;
4330 LOG (" Allocate SQL Connection Handle" );
44- ret = SQLAllocHandle_ptr (SQL_HANDLE_DBC, env , &dbc);
31+ SQLRETURN ret = SQLAllocHandle_ptr (SQL_HANDLE_DBC, getSharedEnvHandle ()-> get () , &dbc);
4532 if (!SQL_SUCCEEDED (ret)) {
46- LOG (" Failed to allocate connection handle" );
4733 throw std::runtime_error (" Failed to allocate connection handle" );
4834 }
4935 _dbc_handle = std::make_shared<SqlHandle>(SQL_HANDLE_DBC, dbc);
36+ }
5037
51- ret = SQLDriverConnect_ptr (dbc, nullptr ,
38+ // Connects to the database
39+ SQLRETURN Connection::connectToDb () {
40+ LOG (" Connecting to database" );
41+ SQLRETURN ret = SQLDriverConnect_ptr (_dbc_handle->get (), nullptr ,
5242 (SQLWCHAR*)_conn_str.c_str (), SQL_NTS,
5343 nullptr , 0 , nullptr , SQL_DRIVER_NOPROMPT);
5444 if (!SQL_SUCCEEDED (ret)) {
55- LOG (" Failed to connect to database" );
56- }
57- else {
58- LOG (" Connected to database successfully" );
45+ throw std::runtime_error (" Failed to connect to database" );
5946 }
47+ LOG (" Connected to database successfully" );
6048 return ret;
6149}
6250
6351SQLRETURN Connection::close () {
52+ if (!_dbc_handle) {
53+ LOG (" No connection handle to close" );
54+ return SQL_SUCCESS;
55+ }
6456 LOG (" Disconnect from MSSQL" );
6557 if (!SQLDisconnect_ptr) {
6658 LOG (" Function pointer not initialized. Loading the driver." );
6759 DriverLoader::getInstance ().loadDriver ();
6860 }
6961
70- return SQLDisconnect_ptr (_dbc_handle->get ());
62+ SQLRETURN ret = SQLDisconnect_ptr (_dbc_handle->get ());
63+ _dbc_handle.reset ();
64+ return ret;
7165}
7266
73- SQLRETURN Connection::end_transaction (SQLSMALLINT completion_type) {
74- LOG (completion_type == SQL_COMMIT ? " End SQL Transaction (Commit)" : " End SQL Transaction (Rollback)" );
75- if (!SQLEndTran_ptr) {
76- LOG (" Function pointer not initialized. Loading the driver." );
77- DriverLoader::getInstance ().loadDriver ();
67+ SQLRETURN Connection::commit () {
68+ if (!_dbc_handle) {
69+ throw std::runtime_error (" Connection handle not allocated" );
70+ }
71+ LOG (" Committing transaction" );
72+ SQLRETURN ret = SQLEndTran_ptr (SQL_HANDLE_DBC, _dbc_handle->get (), SQL_COMMIT);
73+ if (!SQL_SUCCEEDED (ret)) {
74+ throw std::runtime_error (" Failed to commit transaction" );
7875 }
79- return SQLEndTran_ptr (_dbc_handle-> type (), _dbc_handle-> get (), completion_type) ;
76+ return ret ;
8077}
8178
82- SQLRETURN Connection::set_autocommit (bool enable) {
79+ SQLRETURN Connection::rollback () {
80+ if (!_dbc_handle) {
81+ throw std::runtime_error (" Connection handle not allocated" );
82+ }
83+ LOG (" Rolling back transaction" );
84+ SQLRETURN ret = SQLEndTran_ptr (SQL_HANDLE_DBC, _dbc_handle->get (), SQL_ROLLBACK);
85+ if (!SQL_SUCCEEDED (ret)) {
86+ throw std::runtime_error (" Failed to rollback transaction" );
87+ }
88+ return ret;
89+ }
90+
91+ SQLRETURN Connection::setAutocommit (bool enable) {
92+ if (!_dbc_handle) {
93+ throw std::runtime_error (" Connection handle not allocated" );
94+ }
8395 SQLINTEGER value = enable ? SQL_AUTOCOMMIT_ON : SQL_AUTOCOMMIT_OFF;
8496 LOG (" Set SQL Connection Attribute" );
8597 SQLRETURN ret = SQLSetConnectAttr_ptr (_dbc_handle->get (), SQL_ATTR_AUTOCOMMIT, (SQLPOINTER)value, 0 );
8698 if (!SQL_SUCCEEDED (ret)) {
8799 throw std::runtime_error (" Failed to set autocommit mode." );
88100 }
101+ _autocommit = enable;
89102 return ret;
90103}
91104
92- bool Connection::get_autocommit () const {
105+ bool Connection::getAutocommit () const {
106+ if (!_dbc_handle) {
107+ throw std::runtime_error (" Connection handle not allocated" );
108+ }
93109 LOG (" Get SQL Connection Attribute" );
94110 SQLINTEGER value;
95111 SQLINTEGER string_length;
@@ -98,12 +114,41 @@ bool Connection::get_autocommit() const {
98114 return value == SQL_AUTOCOMMIT_ON;
99115}
100116
101- SqlHandlePtr Connection::alloc_statement_handle () {
117+ SqlHandlePtr Connection::allocStatementHandle () {
118+ if (!_dbc_handle) {
119+ throw std::runtime_error (" Connection handle not allocated" );
120+ }
102121 LOG (" Allocating statement handle" );
103122 SQLHANDLE stmt = nullptr ;
104123 SQLRETURN ret = SQLAllocHandle_ptr (SQL_HANDLE_STMT, _dbc_handle->get (), &stmt);
105124 if (!SQL_SUCCEEDED (ret)) {
106125 throw std::runtime_error (" Failed to allocate statement handle" );
107126 }
108127 return std::make_shared<SqlHandle>(SQL_HANDLE_STMT, stmt);
128+ }
129+
130+ SqlHandlePtr Connection::getSharedEnvHandle () {
131+ static std::once_flag flag;
132+ static SqlHandlePtr env_handle;
133+
134+ std::call_once (flag, []() {
135+ LOG (" Allocating environment handle" );
136+ SQLHANDLE env = nullptr ;
137+ if (!SQLAllocHandle_ptr) {
138+ LOG (" Function pointers not initialized, loading driver" );
139+ DriverLoader::getInstance ().loadDriver ();
140+ }
141+ SQLRETURN ret = SQLAllocHandle_ptr (SQL_HANDLE_ENV, SQL_NULL_HANDLE, &env);
142+ if (!SQL_SUCCEEDED (ret)) {
143+ throw std::runtime_error (" Failed to allocate environment handle" );
144+ }
145+ env_handle = std::make_shared<SqlHandle>(SQL_HANDLE_ENV, env);
146+
147+ LOG (" Setting environment attributes" );
148+ ret = SQLSetEnvAttr_ptr (env_handle->get (), SQL_ATTR_ODBC_VERSION, (void *)SQL_OV_ODBC3_80, 0 );
149+ if (!SQL_SUCCEEDED (ret)) {
150+ throw std::runtime_error (" Failed to set environment attribute" );
151+ }
152+ });
153+ return env_handle;
109154}
0 commit comments