Reputation: 543
I'm working with pyodbc with 'autocommit' set to false.
I assume that if only SELECT
sql statements are used (no INSERT
or UPDATE
) then a call to 'commit' function would do nothing with the DB.
Is there any way in pyodbc to determine if there is any changes pending that would be lost if I don't call 'commit'?
I have been thinking to use pyodbc 'getinfo' function which is a wrapper over SQLGetInfo, but can't find any suitable parameter for it.
Actually what I want to do is just notify a user that data in the DB are going to be changed, but I don't want to control what SQL statements have been used (only SELECT
or also UPDATE
& INSERT
) because there are too many places where I would need to check it.
Upvotes: 3
Views: 2913
Reputation: 3824
Unfortunately, pyodbc has not a build-in function to check pending commits.
In SQL Server (starting with 2008) you can check pending commits at database level by using the database_transaction_state
field in sys.dm_tran_database_transactions
table. The transaction's state with pending commit is expected to be 4
. While one without pending commit is expected to be 3
.
From the documentation, the mentioned states are defined as:
3 = The transaction has been initialized but has not generated any log records.
4 = The transaction has generated log records.
The following script checks this idea.
Output
Starting point, no pending transaction or commits
@@TRANCOUNT = 0
database_transaction_state = None
Disable autocommit
@@TRANCOUNT = 1
database_transaction_state = 3
Perform an Insert
@@TRANCOUNT = 1
database_transaction_state = 4
Explicit commit
@@TRANCOUNT = 1
database_transaction_state = 3
Enable autocommit
@@TRANCOUNT = 0
database_transaction_state = None
Code
import pyodbc
conn_param = {
"DRIVER": "{ODBC Driver 13 for SQL Server}",
"SERVER": "(localdb)\\ProjectsV13",
"DATABASE": "master"
}
conn_string = ";".join(["{}={}".format(k, v) for k, v in conn_param.items()])
conn = pyodbc.connect(conn_string, autocommit=True)
cursor = conn.cursor()
def check():
print("\t@@TRANCOUNT = {}".format(
cursor.execute("select @@TRANCOUNT").fetchval()
))
print("\tdatabase_transaction_state = {}".format(
cursor.execute("""
select database_transaction_state
from sys.dm_tran_database_transactions
where transaction_id = CURRENT_TRANSACTION_ID()
and database_id = (
select dbid from sys.sysprocesses where spid = @@SPID
)""").fetchval()
))
cursor.execute("DROP TABLE IF EXISTS testTable")
cursor.execute("SELECT * INTO testTable FROM (VALUES (1), (2), (3)) as x(a)")
print("Starting point, no pending transaction or commits")
check()
print("Disable autocommit")
conn.autocommit = False
check()
print("Perform an Insert")
cursor.execute("INSERT INTO testTable VALUES (4)")
check()
print("Explicit commit")
conn.commit()
check()
print("Enable autocommit")
conn.autocommit = True
check()
cursor.execute("DROP TABLE IF EXISTS testTable")
cursor.close()
conn.close()
Upvotes: 2