77#include " connection.h"
88#include < iostream>
99
10+ SqlHandlePtr Connection::_envHandle = nullptr ;
1011// -------------------------------------------------------------------------------------------------
1112// Implements the Connection class declared in connection.h.
1213// This class wraps low-level ODBC operations like connect/disconnect,
1314// transaction control, and autocommit configuration.
1415// -------------------------------------------------------------------------------------------------
1516Connection::Connection (const std::wstring& conn_str, bool autocommit)
16- : _conn_str(conn_str) , _autocommit(autocommit) {}
17+ : _connStr(conn_str) , _autocommit(autocommit) {
18+ if (!_envHandle) {
19+ LOG (" Allocating environment handle" );
20+ SQLHANDLE env = nullptr ;
21+ if (!SQLAllocHandle_ptr) {
22+ LOG (" Function pointers not initialized, loading driver" );
23+ DriverLoader::getInstance ().loadDriver ();
24+ }
25+ SQLRETURN ret = SQLAllocHandle_ptr (SQL_HANDLE_ENV, SQL_NULL_HANDLE, &env);
26+ if (!SQL_SUCCEEDED (ret)) {
27+ throw std::runtime_error (" Failed to allocate environment handle" );
28+ }
29+ _envHandle = std::make_shared<SqlHandle>(SQL_HANDLE_ENV, env);
1730
18- Connection::~Connection () {
19- close (); // Ensure the connection is closed when the object is destroyed.
31+ LOG (" Setting environment attributes" );
32+ ret = SQLSetEnvAttr_ptr (_envHandle->get (), SQL_ATTR_ODBC_VERSION, (void *)SQL_OV_ODBC3_80, 0 );
33+ if (!SQL_SUCCEEDED (ret)) {
34+ throw std::runtime_error (" Failed to set environment attribute" );
35+ }
36+ }
37+ allocateDbcHandle ();
2038}
2139
22- SQLRETURN Connection::connect () {
23- allocDbcHandle ();
24- return connectToDb ();
40+ Connection::~Connection () {
41+ disconnect ();
2542}
2643
2744// Allocates DBC handle
28- void Connection::allocDbcHandle () {
45+ void Connection::allocateDbcHandle () {
2946 SQLHANDLE dbc = nullptr ;
3047 LOG (" Allocate SQL Connection Handle" );
31- SQLRETURN ret = SQLAllocHandle_ptr (SQL_HANDLE_DBC, getSharedEnvHandle () ->get (), &dbc);
48+ SQLRETURN ret = SQLAllocHandle_ptr (SQL_HANDLE_DBC, _envHandle ->get (), &dbc);
3249 if (!SQL_SUCCEEDED (ret)) {
3350 throw std::runtime_error (" Failed to allocate connection handle" );
3451 }
35- _dbc_handle = std::make_shared<SqlHandle>(SQL_HANDLE_DBC, dbc);
52+ _dbcHandle = std::make_shared<SqlHandle>(SQL_HANDLE_DBC, dbc);
3653}
3754
38- // Connects to the database
39- SQLRETURN Connection::connectToDb () {
55+ void Connection::connect () {
4056 LOG (" Connecting to database" );
41- SQLRETURN ret = SQLDriverConnect_ptr (_dbc_handle->get (), nullptr ,
42- (SQLWCHAR*)_conn_str.c_str (), SQL_NTS,
43- nullptr , 0 , nullptr , SQL_DRIVER_NOPROMPT);
44- if (!SQL_SUCCEEDED (ret)) {
45- throw std::runtime_error (" Failed to connect to database" );
46- }
47- LOG (" Connected to database successfully" );
48- return ret;
57+ SQLRETURN ret = SQLDriverConnect_ptr (
58+ _dbcHandle->get (), nullptr ,
59+ (SQLWCHAR*)_connStr.c_str (), SQL_NTS,
60+ nullptr , 0 , nullptr , SQL_DRIVER_NOPROMPT);
61+ checkError (ret, " SQLDriverConnect failed" );
62+ setAutocommit (_autocommit);
4963}
5064
51- SQLRETURN Connection::close () {
52- if (!_dbc_handle) {
53- LOG (" No connection handle to close" );
54- return SQL_SUCCESS;
55- }
56- LOG (" Disconnect from MSSQL" );
57- if (!SQLDisconnect_ptr) {
58- LOG (" Function pointer not initialized. Loading the driver." );
59- DriverLoader::getInstance ().loadDriver ();
65+ void Connection::disconnect () {
66+ if (_dbcHandle) {
67+ SQLDisconnect_ptr (_dbcHandle->get ());
6068 }
61-
62- SQLRETURN ret = SQLDisconnect_ptr (_dbc_handle->get ());
63- _dbc_handle.reset ();
64- return ret;
6569}
6670
67- SQLRETURN Connection::commit ( ) {
68- if (!_dbc_handle ) {
69- throw std::runtime_error (" Connection handle not allocated " );
71+ void Connection::checkError (SQLRETURN ret, const std::string& msg ) {
72+ if (ret != SQL_SUCCESS && ret != SQL_SUCCESS_WITH_INFO ) {
73+ throw std::runtime_error (" [ODBC Error] " + msg );
7074 }
75+ }
76+
77+ void Connection::commit () {
7178 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" );
75- }
76- return ret;
79+ SQLRETURN ret = SQLEndTran_ptr (SQL_HANDLE_DBC, _dbcHandle->get (), SQL_COMMIT);
80+ checkError (ret, " Failed to commit transaction" );
7781}
7882
79- SQLRETURN Connection::rollback () {
80- if (!_dbc_handle ) {
83+ void Connection::rollback () {
84+ if (!_dbcHandle ) {
8185 throw std::runtime_error (" Connection handle not allocated" );
8286 }
8387 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;
88+ SQLRETURN ret = SQLEndTran_ptr (SQL_HANDLE_DBC, _dbcHandle->get (), SQL_ROLLBACK);
89+ checkError (ret, " Failed to rollback transaction" );
8990}
9091
91- SQLRETURN Connection::setAutocommit (bool enable) {
92- if (!_dbc_handle ) {
92+ void Connection::setAutocommit (bool enable) {
93+ if (!_dbcHandle ) {
9394 throw std::runtime_error (" Connection handle not allocated" );
9495 }
9596 SQLINTEGER value = enable ? SQL_AUTOCOMMIT_ON : SQL_AUTOCOMMIT_OFF;
9697 LOG (" Set SQL Connection Attribute" );
97- SQLRETURN ret = SQLSetConnectAttr_ptr (_dbc_handle->get (), SQL_ATTR_AUTOCOMMIT, (SQLPOINTER)value, 0 );
98- if (!SQL_SUCCEEDED (ret)) {
99- throw std::runtime_error (" Failed to set autocommit mode." );
100- }
98+ SQLRETURN ret = SQLSetConnectAttr_ptr (_dbcHandle->get (), SQL_ATTR_AUTOCOMMIT, (SQLPOINTER)value, 0 );
99+ checkError (ret, " Failed to set autocommit attribute" );
101100 _autocommit = enable;
102- return ret;
103101}
104102
105103bool Connection::getAutocommit () const {
106- if (!_dbc_handle ) {
104+ if (!_dbcHandle ) {
107105 throw std::runtime_error (" Connection handle not allocated" );
108106 }
109107 LOG (" Get SQL Connection Attribute" );
110108 SQLINTEGER value;
111109 SQLINTEGER string_length;
112- SQLGetConnectAttr_ptr (_dbc_handle ->get (), SQL_ATTR_AUTOCOMMIT, &value, sizeof (value), &string_length);
110+ SQLGetConnectAttr_ptr (_dbcHandle ->get (), SQL_ATTR_AUTOCOMMIT, &value, sizeof (value), &string_length);
113111
114112 return value == SQL_AUTOCOMMIT_ON;
115113}
116114
117115SqlHandlePtr Connection::allocStatementHandle () {
118- if (!_dbc_handle ) {
116+ if (!_dbcHandle ) {
119117 throw std::runtime_error (" Connection handle not allocated" );
120118 }
121119 LOG (" Allocating statement handle" );
122120 SQLHANDLE stmt = nullptr ;
123- SQLRETURN ret = SQLAllocHandle_ptr (SQL_HANDLE_STMT, _dbc_handle ->get (), &stmt);
121+ SQLRETURN ret = SQLAllocHandle_ptr (SQL_HANDLE_STMT, _dbcHandle ->get (), &stmt);
124122 if (!SQL_SUCCEEDED (ret)) {
125123 throw std::runtime_error (" Failed to allocate statement handle" );
126124 }
127125 return std::make_shared<SqlHandle>(SQL_HANDLE_STMT, stmt);
128126}
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;
154- }
0 commit comments