Skip to content

Commit a589ef7

Browse files
committed
Fixed #127: a workaround for incorrect pysqlite locking behavior
1 parent 1334eae commit a589ef7

File tree

1 file changed

+54
-24
lines changed

1 file changed

+54
-24
lines changed

pony/orm/dbproviders/sqlite.py

Lines changed: 54 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
from datetime import datetime, date, time, timedelta
88
from random import random
99
from time import strptime
10+
from threading import Lock
1011
from uuid import UUID
1112

1213
from pony.orm import core, dbschema, sqltranslation, dbapiprovider
@@ -184,29 +185,57 @@ class SQLiteProvider(DBAPIProvider):
184185
(buffer, dbapiprovider.BlobConverter),
185186
]
186187

188+
def __init__(provider, *args, **kwargs):
189+
DBAPIProvider.__init__(provider, *args, **kwargs)
190+
provider.transaction_lock = Lock()
191+
187192
@wrap_dbapi_exceptions
188193
def set_transaction_mode(provider, connection, cache):
189194
assert not cache.in_transaction
190-
cursor = connection.cursor()
195+
if cache.immediate:
196+
provider.transaction_lock.acquire()
197+
try:
198+
cursor = connection.cursor()
199+
200+
db_session = cache.db_session
201+
if db_session is not None and db_session.ddl:
202+
cursor.execute('PRAGMA foreign_keys')
203+
fk = cursor.fetchone()
204+
if fk is not None: fk = fk[0]
205+
if fk:
206+
sql = 'PRAGMA foreign_keys = false'
207+
if core.debug: log_orm(sql)
208+
cursor.execute(sql)
209+
cache.saved_fk_state = bool(fk)
210+
assert cache.immediate
191211

192-
db_session = cache.db_session
193-
if db_session is not None and db_session.ddl:
194-
cursor.execute('PRAGMA foreign_keys')
195-
fk = cursor.fetchone()
196-
if fk is not None: fk = fk[0]
197-
if fk:
198-
sql = 'PRAGMA foreign_keys = false'
212+
if cache.immediate:
213+
sql = 'BEGIN IMMEDIATE TRANSACTION'
199214
if core.debug: log_orm(sql)
200215
cursor.execute(sql)
201-
cache.saved_fk_state = bool(fk)
202-
assert cache.immediate
203-
204-
if cache.immediate:
205-
sql = 'BEGIN IMMEDIATE TRANSACTION'
206-
if core.debug: log_orm(sql)
207-
cursor.execute(sql)
208-
cache.in_transaction = True
209-
elif core.debug: log_orm('SWITCH TO AUTOCOMMIT MODE')
216+
cache.in_transaction = True
217+
elif core.debug: log_orm('SWITCH TO AUTOCOMMIT MODE')
218+
finally:
219+
if cache.immediate and not cache.in_transaction:
220+
provider.transaction_lock.release()
221+
222+
def commit(provider, connection, cache=None):
223+
in_transaction = cache is not None and cache.in_transaction
224+
DBAPIProvider.commit(provider, connection, cache)
225+
if in_transaction:
226+
provider.transaction_lock.release()
227+
228+
def rollback(provider, connection, cache=None):
229+
in_transaction = cache is not None and cache.in_transaction
230+
DBAPIProvider.rollback(provider, connection, cache)
231+
if in_transaction:
232+
provider.transaction_lock.release()
233+
234+
def drop(provider, connection, cache=None):
235+
in_transaction = cache is not None and cache.in_transaction
236+
DBAPIProvider.drop(provider, connection, cache)
237+
if in_transaction:
238+
provider.transaction_lock.release()
210239

211240
@wrap_dbapi_exceptions
212241
def release(provider, connection, cache=None):
@@ -230,14 +259,15 @@ def get_pool(provider, filename, create_db=False):
230259
# Database instance is created
231260

232261
# the list of frames:
233-
# 6 - user code: db = Database(...)
234-
# 5 - cut_traceback decorator wrapper
235-
# 4 - cut_traceback decorator
236-
# 3 - pony.orm.Database.__init__() / .bind()
237-
# 2 - pony.orm.Database._bind()
238-
# 1 - pony.dbapiprovider.DBAPIProvider.__init__()
262+
# 7 - user code: db = Database(...)
263+
# 6 - cut_traceback decorator wrapper
264+
# 5 - cut_traceback decorator
265+
# 4 - pony.orm.Database.__init__() / .bind()
266+
# 3 - pony.orm.Database._bind()
267+
# 2 - pony.dbapiprovider.DBAPIProvider.__init__()
268+
# 1 - SQLiteProvider.__init__()
239269
# 0 - pony.dbproviders.sqlite.get_pool()
240-
filename = absolutize_path(filename, frame_depth=6)
270+
filename = absolutize_path(filename, frame_depth=7)
241271
return SQLitePool(filename, create_db)
242272

243273
def table_exists(provider, connection, table_name, case_sensitive=True):

0 commit comments

Comments
 (0)