Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Complex queries with transaction is cancelled/rollbacked. #1057

Closed
zlev-intel opened this issue May 9, 2022 · 6 comments
Closed

Complex queries with transaction is cancelled/rollbacked. #1057

zlev-intel opened this issue May 9, 2022 · 6 comments

Comments

@zlev-intel
Copy link

Please first make sure you have looked at:

Environment

To diagnose, we usually need to know the following, including version numbers. On Windows, be
sure to specify 32-bit Python or 64-bit:

  • Python: 3.8.10
  • pyodbc: 4.0.32
  • OS: Windows
  • DB: Mssql
  • driver: 18

Issue

I'm trying to execute the following (set of) queries:
BEGIN TRAN
SET NOCOUNT ON
IF (SELECT COUNT(*) FROM vaf_infra.mutex WITH (HOLDLOCK)
WHERE row = 0 AND executor_id='00000000-0000-0000-0000-000000000000' ) != 0
BEGIN
UPDATE vaf_infra.mutex SET executor_id=@uuid
WHERE row = 0 AND executor_id='00000000-0000-0000-0000-000000000000'
END
SELECT executor_id FROM vaf_infra.mutex WITH (HOLDLOCK) WHERE row = 0
COMMIT
where table is:
CREATE TABLE cloudcds_dev.vaf_infra.mutex (
executor_id UNIQUEIDENTIFIER NULL
,lock_time DATETIME2 NULL
,row INT NULL DEFAULT (0)
) ON [PRIMARY]
GO
Size of table: 1row; Code used to implement some type of mutex;
It is working OK when send from any DB SW - like dbforge or others, but failed when called from python/pyodbc. Looks like that pyodbc cancels the execution before COMMIT, which caused proper return, but table value is not modified( rollbacked)

@v-chojas
Copy link
Contributor

v-chojas commented May 9, 2022

Could you post an ODBC trace?

@zlev-intel
Copy link
Author

SQL.LOG

@v-chojas
Copy link
Contributor

v-chojas commented May 9, 2022

acd_apis        5f8-5148	ENTER SQLEndTran 
		SQLSMALLINT                  2 <SQL_HANDLE_DBC>
		SQLHANDLE           0x000001C6DF2D8700
		SQLSMALLINT                  1 

1 is rollback. You need to call https://github.com/mkleehammer/pyodbc/wiki/Cursor#commit to cause it to commit the transaction.

@zlev-intel
Copy link
Author

zlev-intel commented May 9, 2022 via email

@v-chojas
Copy link
Contributor

v-chojas commented May 9, 2022

pyODBC by default runs with autocommit off, and the ODBC driver by default will keep a transaction open, so the explicit statements in your query will open a nested transaction. You have committed the inner transaction but the outer (implicit) one remains open and gets rolled back when the handle is freed. Call cursor.commit() to commit the outer one too.

@zlev-intel
Copy link
Author

Thank you, I set AutoCommit on.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants