Skip to content

Commit 65d19a8

Browse files
Saumya Garggargsaumya
authored andcommitted
working interation with access token
1 parent 7f9304b commit 65d19a8

6 files changed

Lines changed: 107 additions & 181 deletions

File tree

mssql_python/connection.py

Lines changed: 4 additions & 111 deletions
Original file line numberDiff line numberDiff line change
@@ -56,16 +56,9 @@ def __init__(self, connection_str: str = "", autocommit: bool = False, attrs_bef
5656
self.connection_str = self._construct_connection_string(
5757
connection_str, **kwargs
5858
)
59-
# self._attrs_before = attrs_before
60-
# self._autocommit = autocommit
61-
# if self._attrs_before != {}:
62-
# self._apply_attrs_before() # Apply pre-connection attributes
63-
# if self._autocommit:
64-
# self.setautocommit(autocommit)
65-
print("Connection string:", self.connection_str)
66-
self._conn = ddbc_bindings.Connection(self.connection_str)
67-
self._conn.connect()
68-
print("Connection established")
59+
self._attrs_before = attrs_before or {}
60+
self._conn = ddbc_bindings.Connection(self.connection_str, autocommit)
61+
self._conn.connect(self._attrs_before)
6962
self._autocommit = autocommit
7063
self.setautocommit(autocommit)
7164

@@ -107,90 +100,6 @@ def _construct_connection_string(self, connection_str: str = "", **kwargs) -> st
107100

108101
return conn_str
109102

110-
# def _apply_attrs_before(self):
111-
# """
112-
# Apply specific pre-connection attributes.
113-
# Currently, this method only processes an attribute with key 1256 (e.g., SQL_COPT_SS_ACCESS_TOKEN)
114-
# if present in `self._attrs_before`. Other attributes are ignored.
115-
116-
# Returns:
117-
# bool: True.
118-
# """
119-
120-
# if ENABLE_LOGGING:
121-
# logger.info("Attempting to apply pre-connection attributes (attrs_before): %s", self._attrs_before)
122-
123-
# if not isinstance(self._attrs_before, dict):
124-
# if self._attrs_before is not None and ENABLE_LOGGING:
125-
# logger.warning(
126-
# f"_attrs_before is of type {type(self._attrs_before).__name__}, "
127-
# f"expected dict. Skipping attribute application."
128-
# )
129-
# elif self._attrs_before is None and ENABLE_LOGGING:
130-
# logger.debug("_attrs_before is None. No pre-connection attributes to apply.")
131-
# return True # Exit if _attrs_before is not a dictionary or is None
132-
133-
# for key, value in self._attrs_before.items():
134-
# ikey = None
135-
# if isinstance(key, int):
136-
# ikey = key
137-
# elif isinstance(key, str) and key.isdigit():
138-
# try:
139-
# ikey = int(key)
140-
# except ValueError:
141-
# if ENABLE_LOGGING:
142-
# logger.debug(
143-
# f"Skipping attribute with key '{key}' in attrs_before: "
144-
# f"could not convert string to int."
145-
# )
146-
# continue # Skip if string key is not a valid integer
147-
# else:
148-
# if ENABLE_LOGGING:
149-
# logger.debug(
150-
# f"Skipping attribute with key '{key}' in attrs_before due to "
151-
# f"unsupported key type: {type(key).__name__}. Expected int or string representation of an int."
152-
# )
153-
# continue # Skip keys that are not int or string representation of an int
154-
155-
# if ikey == ddbc_sql_const.SQL_COPT_SS_ACCESS_TOKEN.value:
156-
# if ENABLE_LOGGING:
157-
# logger.info(
158-
# f"Found attribute {ddbc_sql_const.SQL_COPT_SS_ACCESS_TOKEN.value}. Attempting to set it."
159-
# )
160-
# self._conn.set_attribute(ikey, value)
161-
# if ENABLE_LOGGING:
162-
# logger.info(
163-
# f"Call to set attribute {ddbc_sql_const.SQL_COPT_SS_ACCESS_TOKEN.value} with value '{value}' completed."
164-
# )
165-
# # If you expect only one such key, you could add 'break' here.
166-
# else:
167-
# if ENABLE_LOGGING:
168-
# logger.debug(
169-
# f"Ignoring attribute with key '{key}' (resolved to {ikey}) in attrs_before "
170-
# f"as it is not the target attribute ({ddbc_sql_const.SQL_COPT_SS_ACCESS_TOKEN.value})."
171-
# )
172-
# return True
173-
174-
# def _set_connection_attributes(self, ikey: int, ivalue: any) -> None:
175-
# """
176-
# Set the connection attributes before connecting.
177-
178-
# Args:
179-
# ikey (int): The attribute key to set.
180-
# ivalue (Any): The value to set for the attribute. Can be bytes, bytearray, int, or unicode.
181-
# vallen (int): The length of the value.
182-
183-
# Raises:
184-
# DatabaseError: If there is an error while setting the connection attribute.
185-
# """
186-
187-
# ret = ddbc_bindings.DDBCSQLSetConnectAttr(
188-
# self.hdbc, # Connection handle
189-
# ikey, # Attribute
190-
# ivalue, # Value
191-
# )
192-
# check_error(ddbc_sql_const.SQL_HANDLE_DBC.value, self.hdbc, ret)
193-
194103
@property
195104
def autocommit(self) -> bool:
196105
"""
@@ -208,8 +117,6 @@ def autocommit(self, value: bool) -> None:
208117
value (bool): True to enable autocommit, False to disable it.
209118
Returns:
210119
None
211-
Raises:
212-
DatabaseError: If there is an error while setting the autocommit mode.
213120
"""
214121
self.setautocommit(value)
215122
if ENABLE_LOGGING:
@@ -243,9 +150,6 @@ def cursor(self) -> Cursor:
243150
DatabaseError: If there is an error while creating the cursor.
244151
InterfaceError: If there is an error related to the database interface.
245152
"""
246-
# if self._is_closed():
247-
# # Cannot create a cursor if the connection is closed
248-
# raise Exception("Connection is closed. Cannot create cursor.")
249153
return Cursor(self)
250154

251155
def commit(self) -> None:
@@ -260,10 +164,6 @@ def commit(self) -> None:
260164
Raises:
261165
DatabaseError: If there is an error while committing the transaction.
262166
"""
263-
if self._is_closed():
264-
# Cannot commit if the connection is closed
265-
raise Exception("Connection is closed. Cannot commit.")
266-
267167
# Commit the current transaction
268168
self._conn.commit()
269169
if ENABLE_LOGGING:
@@ -280,10 +180,6 @@ def rollback(self) -> None:
280180
Raises:
281181
DatabaseError: If there is an error while rolling back the transaction.
282182
"""
283-
if self._is_closed():
284-
# Cannot roll back if the connection is closed
285-
raise Exception("Connection is closed. Cannot roll back.")
286-
287183
# Roll back the current transaction
288184
self._conn.rollback()
289185
if ENABLE_LOGGING:
@@ -302,10 +198,7 @@ def close(self) -> None:
302198
Raises:
303199
DatabaseError: If there is an error while closing the connection.
304200
"""
305-
if self._is_closed():
306-
# Connection is already closed
307-
return
201+
# Close the connection
308202
self._conn.close()
309-
310203
if ENABLE_LOGGING:
311204
logger.info("Connection closed successfully.")

mssql_python/cursor.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -415,8 +415,7 @@ def _allocate_statement_handle(self):
415415
"""
416416
Allocate the DDBC statement handle.
417417
"""
418-
self.connection._conn.alloc_statement_handle()
419-
print(f"Statement handle: {self.hstmt}")
418+
self.hstmt = self.connection._conn.alloc_statement_handle()
420419

421420
def _reset_cursor(self) -> None:
422421
"""

mssql_python/pybind/connection/connection.cpp

Lines changed: 46 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7,24 +7,15 @@
77
#include "connection.h"
88
#include <iostream>
99
#include <vector>
10-
11-
<<<<<<< HEAD
1210
#include <pybind11/pybind11.h>
1311

1412
//-------------------------------------------------------------------------------------------------
1513
// Implements the Connection class declared in connection.h.
1614
// This class wraps low-level ODBC operations like connect/disconnect,
1715
// transaction control, and autocommit configuration.
1816
//-------------------------------------------------------------------------------------------------
19-
<<<<<<< HEAD
2017
Connection::Connection(const std::wstring& conn_str, bool autocommit)
2118
: _conn_str(conn_str) , _autocommit(autocommit) {}
22-
=======
23-
Connection::Connection(const std::wstring& conn_str, bool autocommit) : _conn_str(conn_str) , _autocommit(autocommit) {}
24-
=======
25-
Connection::Connection(const std::wstring& conn_str) : _conn_str(conn_str) {}
26-
>>>>>>> fcd64d4 (working flow with c++ connection class)
27-
>>>>>>> 29a7a65 (working flow with c++ connection class)
2819

2920
Connection::~Connection() {
3021
close(); // Ensure the connection is closed when the object is destroyed.
@@ -175,6 +166,52 @@ SqlHandlePtr Connection::allocStatementHandle() {
175166
return std::make_shared<SqlHandle>(SQL_HANDLE_STMT, stmt);
176167
}
177168

169+
SQLRETURN Connection::set_attribute(SQLINTEGER attribute, py::object value) {
170+
LOG("Setting SQL attribute {}");
171+
172+
SQLPOINTER ptr = nullptr;
173+
SQLINTEGER length = 0;
174+
175+
if (py::isinstance<py::int_>(value)) {
176+
int intValue = value.cast<int>();
177+
ptr = reinterpret_cast<SQLPOINTER>(static_cast<uintptr_t>(intValue));
178+
length = SQL_IS_INTEGER;
179+
} else if (py::isinstance<py::bytes>(value) || py::isinstance<py::bytearray>(value)) {
180+
static std::vector<std::string> buffers;
181+
buffers.emplace_back(value.cast<std::string>());
182+
ptr = const_cast<char*>(buffers.back().c_str());
183+
length = static_cast<SQLINTEGER>(buffers.back().size());
184+
} else {
185+
LOG("Unsupported attribute value type");
186+
return SQL_ERROR;
187+
}
188+
189+
SQLRETURN ret = SQLSetConnectAttr_ptr(_dbc_handle->get(), attribute, ptr, length);
190+
if (!SQL_SUCCEEDED(ret)) {
191+
LOG("Failed to set attribute {}");
192+
}
193+
return ret;
194+
}
195+
196+
void Connection::apply_attrs_before(const py::dict& attrs) {
197+
for (const auto& item : attrs) {
198+
int key;
199+
try {
200+
key = py::cast<int>(item.first);
201+
} catch (...) {
202+
continue;
203+
}
204+
205+
//do not hard code the key values
206+
if (key == 1256) {
207+
SQLRETURN ret = set_attribute(key, py::reinterpret_borrow<py::object>(item.second));
208+
if (!SQL_SUCCEEDED(ret)) {
209+
throw std::runtime_error("Failed to set access token before connect");
210+
}
211+
}
212+
}
213+
}
214+
178215
SqlHandlePtr Connection::getSharedEnvHandle() {
179216
static std::once_flag flag;
180217
static SqlHandlePtr env_handle;

mssql_python/pybind/connection/connection.h

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,7 @@ class Connection {
1818
Connection(const std::wstring& conn_str, bool autocommit = false);
1919
~Connection();
2020

21-
// Establish the connection using the stored connection string.
22-
SQLRETURN connect();
21+
SQLRETURN connect(const py::dict& attrs_before = py::dict());
2322

2423
// Close the connection and free resources.
2524
SQLRETURN close();
@@ -46,8 +45,10 @@ class Connection {
4645
std::wstring _conn_str;
4746
SqlHandlePtr _dbc_handle;
4847
bool _autocommit = false;
48+
std::shared_ptr<Connection> _conn;
4949

50-
static SqlHandlePtr getSharedEnvHandle();
50+
SQLRETURN set_attribute(SQLINTEGER attribute, pybind11::object value);
51+
void apply_attrs_before(const pybind11::dict& attrs);
5152
};
5253

5354
#endif // CONNECTION_H

0 commit comments

Comments
 (0)