[pypy-commit] pypy stdlib-2.7.13: No clue if it's a good approach, but trying it out: allow cursors to

arigo pypy.commits at gmail.com
Sun Dec 18 17:29:24 EST 2016


Author: Armin Rigo <arigo at tunes.org>
Branch: stdlib-2.7.13
Changeset: r89170:5d96f9ed88fe
Date: 2016-12-18 23:28 +0100
http://bitbucket.org/pypy/pypy/changeset/5d96f9ed88fe/

Log:	No clue if it's a good approach, but trying it out: allow cursors to
	linger like 2.7.13, but if they cause SQLITE_LOCKED, reset them all
	and try again the operation.

diff --git a/lib-python/2.7/sqlite3/test/regression.py b/lib-python/2.7/sqlite3/test/regression.py
--- a/lib-python/2.7/sqlite3/test/regression.py
+++ b/lib-python/2.7/sqlite3/test/regression.py
@@ -351,10 +351,7 @@
         self.assertRaises(ValueError, cur.execute, " \0select 2")
         self.assertRaises(ValueError, cur.execute, "select 2\0")
 
-    @test_support.impl_detail(pypy=False)
     def CheckCommitCursorReset(self):
-        # This test is for logic added in 2.7.13 which PyPy doesn't
-        # implement.  See http://bugs.python.org/issue29006
         """
         Connection.commit() did reset cursors, which made sqlite3
         to return rows multiple times when fetched from cursors
diff --git a/lib_pypy/_sqlite3.py b/lib_pypy/_sqlite3.py
--- a/lib_pypy/_sqlite3.py
+++ b/lib_pypy/_sqlite3.py
@@ -363,6 +363,14 @@
                 if cursor is not None:
                     cursor._reset = True
 
+    def _reset_all_statements(self):
+        total = 0
+        for weakref in self.__statements:
+            statement = weakref()
+            if statement is not None:
+                total += statement._reset()
+        return total
+
     @_check_thread_wrap
     @_check_closed_wrap
     def __call__(self, sql):
@@ -418,16 +426,6 @@
         if not self._in_transaction:
             return
 
-        # The following line is a KNOWN DIFFERENCE with CPython 2.7.13.
-        # More precisely, the corresponding line was removed in the
-        # version 2.7.13 of CPython, but this is causing troubles for
-        # PyPy (and potentially for CPython too):
-        #
-        #     http://bugs.python.org/issue29006
-        #
-        # So for now, we keep this line.
-        self.__do_all_statements(Statement._reset, False)
-
         statement_star = _ffi.new('sqlite3_stmt **')
         ret = _lib.sqlite3_prepare_v2(self._db, b"COMMIT", -1,
                                       statement_star, _ffi.NULL)
@@ -827,7 +825,26 @@
                 self.__statement._set_params(params)
 
                 # Actually execute the SQL statement
-                ret = _lib.sqlite3_step(self.__statement._statement)
+
+                # NOTE: if we get SQLITE_LOCKED, it's probably because
+                # one of the cursors created previously is still alive
+                # and not reset and the operation we're trying to do
+                # makes Sqlite unhappy about that.  In that case, we
+                # automatically reset all cursors and try again.  This
+                # is not what CPython does!  It is a workaround for a
+                # new feature of 2.7.13.  Previously, all cursors would
+                # be reset at commit(), which makes it unlikely to have
+                # cursors lingering around.  Since 2.7.13, cursors stay
+                # around instead.  This causes problems here---at least:
+                # this is the only place shown by pysqlite tests, and I
+                # can only hope there is no other.
+
+                while True:
+                    ret = _lib.sqlite3_step(self.__statement._statement)
+                    if (ret == _lib.SQLITE_LOCKED and
+                            self.__connection._reset_all_statements()):
+                        continue
+                    break
 
                 if ret == _lib.SQLITE_ROW:
                     if multiple:
@@ -1057,6 +1074,8 @@
         if self._in_use and self._statement:
             _lib.sqlite3_reset(self._statement)
             self._in_use = False
+            return 1
+        return 0
 
     if sys.version_info[0] < 3:
         def __check_decodable(self, param):
diff --git a/pypy/doc/cpython_differences.rst b/pypy/doc/cpython_differences.rst
--- a/pypy/doc/cpython_differences.rst
+++ b/pypy/doc/cpython_differences.rst
@@ -488,11 +488,6 @@
   the rest is kept.  If you return an unexpected string from
   ``__hex__()`` you get an exception (or a crash before CPython 2.7.13).
 
-* The ``sqlite`` module was updated on 2.7.13 to no longer reset all
-  cursors when there is a commit.  This causes troubles for PyPy (and
-  potentially for CPython too), and so for now we didn't port this change:
-  see http://bugs.python.org/issue29006.
-
 .. _`is ignored in PyPy`: http://bugs.python.org/issue14621
 .. _`little point`: http://events.ccc.de/congress/2012/Fahrplan/events/5152.en.html
 .. _`#2072`: https://bitbucket.org/pypy/pypy/issue/2072/


More information about the pypy-commit mailing list