Skip to content

Conversation

bewithgaurav
Copy link
Collaborator

Work Item / Issue Reference

AB#<WORK_ITEM_ID>

GitHub Issue: #182


Summary

This pull request makes improvements to the cursor resource management and error handling in the mssql_python/cursor.py module. The main changes include making the cursor close operation idempotent, refining exception types, and improving logging during cleanup. These updates help ensure more robust and predictable behavior when working with cursors.

Error handling improvements:

  • Changed the exception raised when attempting to close an already closed cursor from a generic Exception to a more specific ProgrammingError, providing clearer feedback to users.
  • Updated the import statement to use ProgrammingError instead of InterfaceError, aligning with the new error handling approach.

Resource cleanup and logging:

  • Improved the destructor (__del__) to check for the correct closed attribute and made sure no exception is raised if the cursor is already closed, enhancing reliability during garbage collection.
  • Changed the logging level in the destructor from 'error' to 'debug' for exceptions during cleanup, reducing unnecessary noise in error logs.

@Copilot Copilot AI review requested due to automatic review settings August 18, 2025 07:19
@github-actions github-actions bot added the pr-size: small Minimal code update label Aug 18, 2025
Copy link
Contributor

@Copilot Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR improves cursor resource management and error handling in the mssql_python cursor module. The changes make cursor operations more robust by implementing idempotent close behavior and better cleanup procedures.

  • Enhanced cursor close operation to be idempotent and use more specific exception types
  • Fixed destructor to properly check the closed attribute instead of _closed
  • Improved logging during cleanup by reducing error noise to debug level

Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.


Raises:
Error: If any operation is attempted with the cursor after it is closed.
"""
if self.closed:
raise Exception("Cursor is already closed.")
raise ProgrammingError("Cursor is already closed.")
Copy link
Preview

Copilot AI Aug 18, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The close() method documentation states it should be idempotent ('subsequent calls have no effect'), but the implementation still raises an exception when called on an already closed cursor. Consider removing this exception to make the method truly idempotent as documented.

Copilot uses AI. Check for mistakes.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The "idempotency" in this context means that calling close() multiple times won't free resources twice or cause corruption - the first call frees resources and subsequent calls raise a predictable exception. This is actually the standard behavior in pyodbc as well. Added a comment here specifying the same.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Deleted unwanted whl file which was committed earlier

@github-actions github-actions bot added pr-size: small Minimal code update and removed pr-size: small Minimal code update labels Aug 18, 2025
@github-actions github-actions bot added pr-size: medium Moderate update size and removed pr-size: small Minimal code update labels Aug 18, 2025
@github-actions github-actions bot added pr-size: medium Moderate update size and removed pr-size: medium Moderate update size labels Aug 18, 2025
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

cleaned this up as well, this is already present inside vcredist

@github-actions github-actions bot added pr-size: medium Moderate update size and removed pr-size: medium Moderate update size labels Aug 18, 2025
@github-actions github-actions bot added pr-size: medium Moderate update size and removed pr-size: medium Moderate update size labels Aug 18, 2025
@github-actions github-actions bot added pr-size: medium Moderate update size and removed pr-size: medium Moderate update size labels Aug 18, 2025
"""
if "_closed" not in self.__dict__ or not self._closed:
if "closed" not in self.__dict__ or not self.closed:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can't we define self.closed in the constructor, so you can simply check if not self.closed:`?
This may avoid reliance on dict, and guards against subtle bugs if the attribute is missing.

Let me know if I am missing anything wrt to dict if its used anywhere else.

@@ -457,7 +461,7 @@ def _check_closed(self):
Error: If the cursor is closed.
"""
if self.closed:
raise Exception("Operation cannot be performed: the cursor is closed.")
raise ProgrammingError("Cursor is already closed.", "")
Copy link
Contributor

@sumitmsft sumitmsft Aug 24, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These changes still keeps cursor.close() non‑idempotent while the comments claims it is idempotent.

close() now calls self._check_closed() at the start.
_check_closed() raises ProgrammingError when self.closed is True.
Therefore a second close() raises instead of being a no‑op. That is NOT idempotent.

First, the issue raised in 183 requires no-op\no error during second close of the cursor. Secondly, DB-API 2.0 convention defines calling .close() multiple times must be safe (no exception).

We can keep _check_closed() raising ProgrammingError only for operational methods (execute/fetch) after closure - NOT for close() itself.

Fix the tests to make sure double closing of cursor is silent.

Copy link
Contributor

@sumitmsft sumitmsft left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Left a couple of comments.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
pr-size: medium Moderate update size
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants