Author: Armin Rigo <[email protected]>
Branch:
Changeset: r76677:ba063d80a04f
Date: 2015-04-01 15:25 +0200
http://bitbucket.org/pypy/pypy/changeset/ba063d80a04f/
Log: Test and fix for issue #2006
diff --git a/lib_pypy/_sqlite3.py b/lib_pypy/_sqlite3.py
--- a/lib_pypy/_sqlite3.py
+++ b/lib_pypy/_sqlite3.py
@@ -454,6 +454,7 @@
self.__cursors_counter = 0
self.__statements = []
self.__statements_counter = 0
+ self.__rawstatements = set()
self._statement_cache = _StatementCache(self, cached_statements)
self.__func_cache = {}
@@ -483,6 +484,14 @@
self.__do_all_statements(Statement._finalize, True)
+ # depending on when this close() is called, the statements' weakrefs
+ # may be already dead, even though Statement.__del__() was not called
+ # yet. In this case, self.__rawstatements is not empty.
+ if self.__rawstatements is not None:
+ for stmt in list(self.__rawstatements):
+ self._finalize_raw_statement(stmt)
+ self.__rawstatements = None
+
if self._db:
ret = _lib.sqlite3_close(self._db)
if ret != _lib.SQLITE_OK:
@@ -562,6 +571,7 @@
self.__cursors = [r for r in self.__cursors if r() is not None]
def _remember_statement(self, statement):
+ self.__rawstatements.add(statement._statement)
self.__statements.append(weakref.ref(statement))
self.__statements_counter += 1
if self.__statements_counter < 200:
@@ -569,6 +579,11 @@
self.__statements_counter = 0
self.__statements = [r for r in self.__statements if r() is not None]
+ def _finalize_raw_statement(self, _statement):
+ if self.__rawstatements is not None:
+ self.__rawstatements.remove(_statement)
+ _lib.sqlite3_finalize(_statement)
+
def __do_all_statements(self, action, reset_cursors):
for weakref in self.__statements:
statement = weakref()
@@ -1199,7 +1214,6 @@
def __init__(self, connection, sql):
self.__con = connection
- self.__con._remember_statement(self)
self._in_use = False
@@ -1232,6 +1246,7 @@
ret = _lib.sqlite3_prepare_v2(self.__con._db, c_sql, -1,
statement_star, next_char)
self._statement = statement_star[0]
+ self.__con._remember_statement(self)
if ret == _lib.SQLITE_OK and not self._statement:
# an empty statement, work around that, as it's the least trouble
@@ -1250,11 +1265,11 @@
def __del__(self):
if self._statement:
- _lib.sqlite3_finalize(self._statement)
+ self.__con._finalize_raw_statement(self._statement)
def _finalize(self):
if self._statement:
- _lib.sqlite3_finalize(self._statement)
+ self.__con._finalize_raw_statement(self._statement)
self._statement = None
self._in_use = False
diff --git a/pypy/module/test_lib_pypy/test_sqlite3.py
b/pypy/module/test_lib_pypy/test_sqlite3.py
--- a/pypy/module/test_lib_pypy/test_sqlite3.py
+++ b/pypy/module/test_lib_pypy/test_sqlite3.py
@@ -276,6 +276,32 @@
exc = raises(ValueError, cur.execute, "select 2\0")
assert str(exc.value) == "the query contains a null character"
+ import sqlite3
+
+ def test_close_in_del_ordering(self):
+ import gc
+ class SQLiteBackend(object):
+ success = False
+ def __init__(self):
+ self.connection = _sqlite3.connect(":memory:")
+ def close(self):
+ self.connection.close()
+ def __del__(self):
+ self.close()
+ SQLiteBackend.success = True
+ def create_db_if_needed(self):
+ conn = self.connection
+ cursor = conn.cursor()
+ cursor.execute("""
+ create table if not exists nameoftable(value text)
+ """)
+ cursor.close()
+ conn.commit()
+ SQLiteBackend().create_db_if_needed()
+ gc.collect()
+ gc.collect()
+ assert SQLiteBackend.success
+
class TestSQLiteHost(BaseTestSQLite):
def setup_class(cls):
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit