55// taken up in future
66
77#include " connection.h"
8+ #include " connection_pool.h"
89#include < vector>
910#include < pybind11/pybind11.h>
1011
@@ -16,8 +17,8 @@ SqlHandlePtr Connection::_envHandle = nullptr;
1617// This class wraps low-level ODBC operations like connect/disconnect,
1718// transaction control, and autocommit configuration.
1819// -------------------------------------------------------------------------------------------------
19- Connection::Connection (const std::wstring& conn_str, bool autocommit )
20- : _connStr(conn_str) , _autocommit(autocommit ) {
20+ Connection::Connection (const std::wstring& conn_str, bool use_pool )
21+ : _connStr(conn_str), _autocommit(false ), _fromPool(use_pool ) {
2122 if (!_envHandle) {
2223 LOG (" Allocating environment handle" );
2324 SQLHANDLE env = nullptr ;
@@ -64,6 +65,7 @@ void Connection::connect(const py::dict& attrs_before) {
6465 (SQLWCHAR*)_connStr.c_str (), SQL_NTS,
6566 nullptr , 0 , nullptr , SQL_DRIVER_NOPROMPT);
6667 checkError (ret);
68+ updateLastUsed ();
6769}
6870
6971void Connection::disconnect () {
@@ -91,6 +93,7 @@ void Connection::commit() {
9193 if (!_dbcHandle) {
9294 ThrowStdException (" Connection handle not allocated" );
9395 }
96+ updateLastUsed ();
9497 LOG (" Committing transaction" );
9598 SQLRETURN ret = SQLEndTran_ptr (SQL_HANDLE_DBC, _dbcHandle->get (), SQL_COMMIT);
9699 checkError (ret);
@@ -100,6 +103,7 @@ void Connection::rollback() {
100103 if (!_dbcHandle) {
101104 ThrowStdException (" Connection handle not allocated" );
102105 }
106+ updateLastUsed ();
103107 LOG (" Rolling back transaction" );
104108 SQLRETURN ret = SQLEndTran_ptr (SQL_HANDLE_DBC, _dbcHandle->get (), SQL_ROLLBACK);
105109 checkError (ret);
@@ -132,6 +136,7 @@ SqlHandlePtr Connection::allocStatementHandle() {
132136 if (!_dbcHandle) {
133137 ThrowStdException (" Connection handle not allocated" );
134138 }
139+ updateLastUsed ();
135140 LOG (" Allocating statement handle" );
136141 SQLHANDLE stmt = nullptr ;
137142 SQLRETURN ret = SQLAllocHandle_ptr (SQL_HANDLE_STMT, _dbcHandle->get (), &stmt);
@@ -185,4 +190,99 @@ void Connection::applyAttrsBefore(const py::dict& attrs) {
185190 }
186191 }
187192 }
188- }
193+ }
194+
195+ bool Connection::isAlive () const {
196+ if (!_dbcHandle) {
197+ ThrowStdException (" Connection handle not allocated" );
198+ }
199+ SQLUINTEGER status;
200+ SQLRETURN ret = SQLGetConnectAttr_ptr (_dbcHandle->get (), SQL_ATTR_CONNECTION_DEAD,
201+ &status, 0 , nullptr );
202+ return SQL_SUCCEEDED (ret) && status == SQL_CD_FALSE;
203+ }
204+
205+ bool Connection::reset () {
206+ if (!_dbcHandle) {
207+ ThrowStdException (" Connection handle not allocated" );
208+ }
209+ LOG (" Resetting connection via SQL_ATTR_RESET_CONNECTION" );
210+ SQLULEN reset = SQL_TRUE;
211+ SQLRETURN ret = SQLSetConnectAttr_ptr (
212+ _dbcHandle->get (),
213+ SQL_ATTR_RESET_CONNECTION,
214+ (SQLPOINTER)SQL_RESET_CONNECTION_YES,
215+ SQL_IS_INTEGER);
216+ if (!SQL_SUCCEEDED (ret)) {
217+ LOG (" Failed to reset connection. Marking as dead." );
218+ disconnect ();
219+ return false ;
220+ }
221+ updateLastUsed ();
222+ return true ;
223+ }
224+
225+ void Connection::updateLastUsed () {
226+ _lastUsed = std::chrono::steady_clock::now ();
227+ }
228+
229+ std::chrono::steady_clock::time_point Connection::lastUsed () const {
230+ return _lastUsed;
231+ }
232+
233+ ConnectionHandle::ConnectionHandle (const std::wstring& connStr, bool usePool, const py::dict& attrsBefore)
234+ : _connStr(connStr), _usePool(usePool) {
235+ if (_usePool) {
236+ _conn = ConnectionPoolManager::getInstance ().acquireConnection (connStr, attrsBefore);
237+ } else {
238+ _conn = std::make_shared<Connection>(connStr, false );
239+ _conn->connect (attrsBefore);
240+ }
241+ }
242+
243+ void ConnectionHandle::close () {
244+ if (!_conn) {
245+ ThrowStdException (" Connection object is not initialized" );
246+ }
247+ if (_usePool) {
248+ ConnectionPoolManager::getInstance ().returnConnection (_connStr, _conn);
249+ } else {
250+ _conn->disconnect ();
251+ }
252+ _conn = nullptr ;
253+ }
254+
255+ void ConnectionHandle::commit () {
256+ if (!_conn) {
257+ ThrowStdException (" Connection object is not initialized" );
258+ }
259+ _conn->commit ();
260+ }
261+
262+ void ConnectionHandle::rollback () {
263+ if (!_conn) {
264+ ThrowStdException (" Connection object is not initialized" );
265+ }
266+ _conn->rollback ();
267+ }
268+
269+ void ConnectionHandle::setAutocommit (bool enabled) {
270+ if (!_conn) {
271+ ThrowStdException (" Connection object is not initialized" );
272+ }
273+ _conn->setAutocommit (enabled);
274+ }
275+
276+ bool ConnectionHandle::getAutocommit () const {
277+ if (!_conn) {
278+ ThrowStdException (" Connection object is not initialized" );
279+ }
280+ return _conn->getAutocommit ();
281+ }
282+
283+ SqlHandlePtr ConnectionHandle::allocStatementHandle () {
284+ if (!_conn) {
285+ ThrowStdException (" Connection object is not initialized" );
286+ }
287+ return _conn->allocStatementHandle ();
288+ }
0 commit comments