Skip to content

Commit 7f9304b

Browse files
Saumya Garggargsaumya
authored andcommitted
working flow with c++ connection class
1 parent 998b25e commit 7f9304b

5 files changed

Lines changed: 162 additions & 243 deletions

File tree

mssql_python/connection.py

Lines changed: 104 additions & 217 deletions
Original file line numberDiff line numberDiff line change
@@ -53,14 +53,20 @@ def __init__(self, connection_str: str = "", autocommit: bool = False, attrs_bef
5353
preparing it for further operations such as connecting to the
5454
database, executing queries, etc.
5555
"""
56-
self.henv = None
57-
self.hdbc = None
5856
self.connection_str = self._construct_connection_string(
5957
connection_str, **kwargs
6058
)
61-
self._attrs_before = attrs_before
62-
self._autocommit = autocommit # Initialize _autocommit before calling _initializer
63-
self._initializer()
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")
69+
self._autocommit = autocommit
6470
self.setautocommit(autocommit)
6571

6672
def _construct_connection_string(self, connection_str: str = "", **kwargs) -> str:
@@ -100,177 +106,90 @@ def _construct_connection_string(self, connection_str: str = "", **kwargs) -> st
100106
logger.info("Final connection string: %s", conn_str)
101107

102108
return conn_str
103-
104-
def _is_closed(self) -> bool:
105-
"""
106-
Check if the connection is closed.
107-
108-
Returns:
109-
bool: True if the connection is closed, False otherwise.
110-
"""
111-
return self.hdbc is None
112109

113-
def _initializer(self) -> None:
114-
"""
115-
Initialize the environment and connection handles.
116-
117-
This method is responsible for setting up the environment and connection
118-
handles, allocating memory for them, and setting the necessary attributes.
119-
It should be called before establishing a connection to the database.
120-
"""
121-
self._allocate_environment_handle()
122-
self._set_environment_attributes()
123-
self._allocate_connection_handle()
124-
if self._attrs_before != {}:
125-
self._apply_attrs_before() # Apply pre-connection attributes
126-
if self._autocommit:
127-
self._set_connection_attributes(
128-
ddbc_sql_const.SQL_ATTR_AUTOCOMMIT.value,
129-
ddbc_sql_const.SQL_AUTOCOMMIT_ON.value,
130-
)
131-
self._connect_to_db()
132-
133-
def _apply_attrs_before(self):
134-
"""
135-
Apply specific pre-connection attributes.
136-
Currently, this method only processes an attribute with key 1256 (e.g., SQL_COPT_SS_ACCESS_TOKEN)
137-
if present in `self._attrs_before`. Other attributes are ignored.
138-
139-
Returns:
140-
bool: True.
141-
"""
142-
143-
if ENABLE_LOGGING:
144-
logger.info("Attempting to apply pre-connection attributes (attrs_before): %s", self._attrs_before)
145-
146-
if not isinstance(self._attrs_before, dict):
147-
if self._attrs_before is not None and ENABLE_LOGGING:
148-
logger.warning(
149-
f"_attrs_before is of type {type(self._attrs_before).__name__}, "
150-
f"expected dict. Skipping attribute application."
151-
)
152-
elif self._attrs_before is None and ENABLE_LOGGING:
153-
logger.debug("_attrs_before is None. No pre-connection attributes to apply.")
154-
return True # Exit if _attrs_before is not a dictionary or is None
155-
156-
for key, value in self._attrs_before.items():
157-
ikey = None
158-
if isinstance(key, int):
159-
ikey = key
160-
elif isinstance(key, str) and key.isdigit():
161-
try:
162-
ikey = int(key)
163-
except ValueError:
164-
if ENABLE_LOGGING:
165-
logger.debug(
166-
f"Skipping attribute with key '{key}' in attrs_before: "
167-
f"could not convert string to int."
168-
)
169-
continue # Skip if string key is not a valid integer
170-
else:
171-
if ENABLE_LOGGING:
172-
logger.debug(
173-
f"Skipping attribute with key '{key}' in attrs_before due to "
174-
f"unsupported key type: {type(key).__name__}. Expected int or string representation of an int."
175-
)
176-
continue # Skip keys that are not int or string representation of an int
177-
178-
if ikey == ddbc_sql_const.SQL_COPT_SS_ACCESS_TOKEN.value:
179-
if ENABLE_LOGGING:
180-
logger.info(
181-
f"Found attribute {ddbc_sql_const.SQL_COPT_SS_ACCESS_TOKEN.value}. Attempting to set it."
182-
)
183-
self._set_connection_attributes(ikey, value)
184-
if ENABLE_LOGGING:
185-
logger.info(
186-
f"Call to set attribute {ddbc_sql_const.SQL_COPT_SS_ACCESS_TOKEN.value} with value '{value}' completed."
187-
)
188-
# If you expect only one such key, you could add 'break' here.
189-
else:
190-
if ENABLE_LOGGING:
191-
logger.debug(
192-
f"Ignoring attribute with key '{key}' (resolved to {ikey}) in attrs_before "
193-
f"as it is not the target attribute ({ddbc_sql_const.SQL_COPT_SS_ACCESS_TOKEN.value})."
194-
)
195-
return True
196-
197-
def _allocate_environment_handle(self):
198-
"""
199-
Allocate the environment handle.
200-
"""
201-
ret, handle = ddbc_bindings.DDBCSQLAllocHandle(
202-
ddbc_sql_const.SQL_HANDLE_ENV.value, # SQL environment handle type
203-
None
204-
)
205-
check_error(ddbc_sql_const.SQL_HANDLE_ENV.value, handle, ret)
206-
self.henv = handle
207-
208-
def _set_environment_attributes(self):
209-
"""
210-
Set the environment attributes.
211-
"""
212-
ret = ddbc_bindings.DDBCSQLSetEnvAttr(
213-
self.henv, # Use the wrapper class
214-
ddbc_sql_const.SQL_ATTR_DDBC_VERSION.value, # Attribute
215-
ddbc_sql_const.SQL_OV_DDBC3_80.value, # String Length
216-
0, # Null-terminated string
217-
)
218-
check_error(ddbc_sql_const.SQL_HANDLE_ENV.value, self.henv, ret)
219-
220-
def _allocate_connection_handle(self):
221-
"""
222-
Allocate the connection handle.
223-
"""
224-
ret, handle = ddbc_bindings.DDBCSQLAllocHandle(
225-
ddbc_sql_const.SQL_HANDLE_DBC.value, # SQL connection handle type
226-
self.henv
227-
)
228-
check_error(ddbc_sql_const.SQL_HANDLE_DBC.value, handle, ret)
229-
self.hdbc = handle
230-
231-
def _set_connection_attributes(self, ikey: int, ivalue: any) -> None:
232-
"""
233-
Set the connection attributes before connecting.
234-
235-
Args:
236-
ikey (int): The attribute key to set.
237-
ivalue (Any): The value to set for the attribute. Can be bytes, bytearray, int, or unicode.
238-
vallen (int): The length of the value.
239-
240-
Raises:
241-
DatabaseError: If there is an error while setting the connection attribute.
242-
"""
243-
244-
ret = ddbc_bindings.DDBCSQLSetConnectAttr(
245-
self.hdbc, # Connection handle
246-
ikey, # Attribute
247-
ivalue, # Value
248-
)
249-
check_error(ddbc_sql_const.SQL_HANDLE_DBC.value, self.hdbc, ret)
250-
251-
def _connect_to_db(self) -> None:
252-
"""
253-
Establish a connection to the database.
254-
255-
This method is responsible for creating a connection to the specified database.
256-
It does not take any arguments and does not return any value. The connection
257-
details such as database name, user credentials, host, and port should be
258-
configured within the class or passed during the class instantiation.
259-
260-
Raises:
261-
DatabaseError: If there is an error while trying to connect to the database.
262-
InterfaceError: If there is an error related to the database interface.
263-
"""
264-
if ENABLE_LOGGING:
265-
logger.info("Connecting to the database")
266-
ret = ddbc_bindings.DDBCSQLDriverConnect(
267-
self.hdbc, # Connection handle (wrapper)
268-
0, # Window handle
269-
self.connection_str, # Connection string
270-
)
271-
check_error(ddbc_sql_const.SQL_HANDLE_DBC.value, self.hdbc, ret)
272-
if ENABLE_LOGGING:
273-
logger.info("Connection established successfully.")
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)
274193

275194
@property
276195
def autocommit(self) -> bool:
@@ -279,14 +198,7 @@ def autocommit(self) -> bool:
279198
Returns:
280199
bool: True if autocommit is enabled, False otherwise.
281200
"""
282-
autocommit_mode = ddbc_bindings.DDBCSQLGetConnectionAttr(
283-
self.hdbc, # Connection handle (wrapper)
284-
ddbc_sql_const.SQL_ATTR_AUTOCOMMIT.value, # Attribute
285-
)
286-
check_error(
287-
ddbc_sql_const.SQL_HANDLE_DBC.value, self.hdbc, autocommit_mode
288-
)
289-
return autocommit_mode == ddbc_sql_const.SQL_AUTOCOMMIT_ON.value
201+
return self._conn.get_autocommit()
290202

291203
@autocommit.setter
292204
def autocommit(self, value: bool) -> None:
@@ -299,17 +211,7 @@ def autocommit(self, value: bool) -> None:
299211
Raises:
300212
DatabaseError: If there is an error while setting the autocommit mode.
301213
"""
302-
ret = ddbc_bindings.DDBCSQLSetConnectAttr(
303-
self.hdbc, # Connection handle
304-
ddbc_sql_const.SQL_ATTR_AUTOCOMMIT.value, # Attribute
305-
(
306-
ddbc_sql_const.SQL_AUTOCOMMIT_ON.value
307-
if value
308-
else ddbc_sql_const.SQL_AUTOCOMMIT_OFF.value
309-
), # Value
310-
)
311-
check_error(ddbc_sql_const.SQL_HANDLE_DBC.value, self.hdbc, ret)
312-
self._autocommit = value
214+
self.setautocommit(value)
313215
if ENABLE_LOGGING:
314216
logger.info("Autocommit mode set to %s.", value)
315217

@@ -323,7 +225,8 @@ def setautocommit(self, value: bool = True) -> None:
323225
Raises:
324226
DatabaseError: If there is an error while setting the autocommit mode.
325227
"""
326-
self.autocommit = value
228+
self._conn.set_autocommit(value)
229+
self._autocommit = value
327230

328231
def cursor(self) -> Cursor:
329232
"""
@@ -340,9 +243,9 @@ def cursor(self) -> Cursor:
340243
DatabaseError: If there is an error while creating the cursor.
341244
InterfaceError: If there is an error related to the database interface.
342245
"""
343-
if self._is_closed():
344-
# Cannot create a cursor if the connection is closed
345-
raise Exception("Connection is closed. Cannot create cursor.")
246+
# if self._is_closed():
247+
# # Cannot create a cursor if the connection is closed
248+
# raise Exception("Connection is closed. Cannot create cursor.")
346249
return Cursor(self)
347250

348251
def commit(self) -> None:
@@ -362,12 +265,7 @@ def commit(self) -> None:
362265
raise Exception("Connection is closed. Cannot commit.")
363266

364267
# Commit the current transaction
365-
ret = ddbc_bindings.DDBCSQLEndTran(
366-
ddbc_sql_const.SQL_HANDLE_DBC.value, # Handle type
367-
self.hdbc, # Connection handle (wrapper)
368-
ddbc_sql_const.SQL_COMMIT.value, # Commit the transaction
369-
)
370-
check_error(ddbc_sql_const.SQL_HANDLE_DBC.value, self.hdbc, ret)
268+
self._conn.commit()
371269
if ENABLE_LOGGING:
372270
logger.info("Transaction committed successfully.")
373271

@@ -387,12 +285,7 @@ def rollback(self) -> None:
387285
raise Exception("Connection is closed. Cannot roll back.")
388286

389287
# Roll back the current transaction
390-
ret = ddbc_bindings.DDBCSQLEndTran(
391-
ddbc_sql_const.SQL_HANDLE_DBC.value, # Handle type
392-
self.hdbc, # Connection handle (wrapper)
393-
ddbc_sql_const.SQL_ROLLBACK.value, # Roll back the transaction
394-
)
395-
check_error(ddbc_sql_const.SQL_HANDLE_DBC.value, self.hdbc, ret)
288+
self._conn.rollback()
396289
if ENABLE_LOGGING:
397290
logger.info("Transaction rolled back successfully.")
398291

@@ -412,13 +305,7 @@ def close(self) -> None:
412305
if self._is_closed():
413306
# Connection is already closed
414307
return
415-
# Disconnect from the database
416-
ret = ddbc_bindings.DDBCSQLDisconnect(self.hdbc)
417-
check_error(ddbc_sql_const.SQL_HANDLE_DBC.value, self.hdbc, ret)
418-
419-
# Set the reference to None to trigger destructor
420-
self.hdbc.free()
421-
self.hdbc = None
308+
self._conn.close()
422309

423310
if ENABLE_LOGGING:
424311
logger.info("Connection closed successfully.")

0 commit comments

Comments
 (0)