[Python-checkins] cpython: Issue #16864: Cursor.lastrowid now supports REPLACE statement

berker.peksag python-checkins at python.org
Tue Jun 14 08:25:47 EDT 2016


https://hg.python.org/cpython/rev/2126e8cbc12f
changeset:   102030:2126e8cbc12f
user:        Berker Peksag <berker.peksag at gmail.com>
date:        Tue Jun 14 15:25:36 2016 +0300
summary:
  Issue #16864: Cursor.lastrowid now supports REPLACE statement

Initial patch by Alex LordThorsen.

files:
  Doc/library/sqlite3.rst   |  13 ++++++-
  Doc/whatsnew/3.6.rst      |   7 ++++
  Lib/sqlite3/test/dbapi.py |  43 ++++++++++++++++++++++++++-
  Misc/ACKS                 |   1 +
  Misc/NEWS                 |   3 +
  Modules/_sqlite/cursor.c  |   4 +-
  6 files changed, 66 insertions(+), 5 deletions(-)


diff --git a/Doc/library/sqlite3.rst b/Doc/library/sqlite3.rst
--- a/Doc/library/sqlite3.rst
+++ b/Doc/library/sqlite3.rst
@@ -629,9 +629,16 @@
    .. attribute:: lastrowid
 
       This read-only attribute provides the rowid of the last modified row. It is
-      only set if you issued an ``INSERT`` statement using the :meth:`execute`
-      method. For operations other than ``INSERT`` or when :meth:`executemany` is
-      called, :attr:`lastrowid` is set to :const:`None`.
+      only set if you issued an ``INSERT`` or a ``REPLACE`` statement using the
+      :meth:`execute` method.  For operations other than ``INSERT`` or
+      ``REPLACE`` or when :meth:`executemany` is called, :attr:`lastrowid` is
+      set to :const:`None`.
+
+      If the ``INSERT`` or ``REPLACE`` statement failed to insert the previous
+      successful rowid is returned.
+
+      .. versionchanged:: 3.6
+         Added support for the ``REPLACE`` statement.
 
    .. attribute:: description
 
diff --git a/Doc/whatsnew/3.6.rst b/Doc/whatsnew/3.6.rst
--- a/Doc/whatsnew/3.6.rst
+++ b/Doc/whatsnew/3.6.rst
@@ -339,6 +339,13 @@
 (Contributed by Wolfgang Langner in :issue:`26587`).
 
 
+sqlite3
+-------
+
+* :attr:`sqlite3.Cursor.lastrowid` now supports the ``REPLACE`` statement.
+  (Contributed by Alex LordThorsen in :issue:`16864`.)
+
+
 socketserver
 ------------
 
diff --git a/Lib/sqlite3/test/dbapi.py b/Lib/sqlite3/test/dbapi.py
--- a/Lib/sqlite3/test/dbapi.py
+++ b/Lib/sqlite3/test/dbapi.py
@@ -188,7 +188,10 @@
     def setUp(self):
         self.cx = sqlite.connect(":memory:")
         self.cu = self.cx.cursor()
-        self.cu.execute("create table test(id integer primary key, name text, income number)")
+        self.cu.execute(
+            "create table test(id integer primary key, name text, "
+            "income number, unique_test text unique)"
+        )
         self.cu.execute("insert into test(name) values (?)", ("foo",))
 
     def tearDown(self):
@@ -462,6 +465,44 @@
         with self.assertRaises(TypeError):
             cur = sqlite.Cursor(foo)
 
+    def CheckLastRowIDOnReplace(self):
+        """
+        INSERT OR REPLACE and REPLACE INTO should produce the same behavior.
+        """
+        sql = '{} INTO test(id, unique_test) VALUES (?, ?)'
+        for statement in ('INSERT OR REPLACE', 'REPLACE'):
+            with self.subTest(statement=statement):
+                self.cu.execute(sql.format(statement), (1, 'foo'))
+                self.assertEqual(self.cu.lastrowid, 1)
+
+    def CheckLastRowIDOnIgnore(self):
+        self.cu.execute(
+            "insert or ignore into test(unique_test) values (?)",
+            ('test',))
+        self.assertEqual(self.cu.lastrowid, 2)
+        self.cu.execute(
+            "insert or ignore into test(unique_test) values (?)",
+            ('test',))
+        self.assertEqual(self.cu.lastrowid, 2)
+
+    def CheckLastRowIDInsertOR(self):
+        results = []
+        for statement in ('FAIL', 'ABORT', 'ROLLBACK'):
+            sql = 'INSERT OR {} INTO test(unique_test) VALUES (?)'
+            with self.subTest(statement='INSERT OR {}'.format(statement)):
+                self.cu.execute(sql.format(statement), (statement,))
+                results.append((statement, self.cu.lastrowid))
+                with self.assertRaises(sqlite.IntegrityError):
+                    self.cu.execute(sql.format(statement), (statement,))
+                results.append((statement, self.cu.lastrowid))
+        expected = [
+            ('FAIL', 2), ('FAIL', 2),
+            ('ABORT', 3), ('ABORT', 3),
+            ('ROLLBACK', 4), ('ROLLBACK', 4),
+        ]
+        self.assertEqual(results, expected)
+
+
 @unittest.skipUnless(threading, 'This test requires threading.')
 class ThreadTests(unittest.TestCase):
     def setUp(self):
diff --git a/Misc/ACKS b/Misc/ACKS
--- a/Misc/ACKS
+++ b/Misc/ACKS
@@ -895,6 +895,7 @@
 Hugo Lopes Tavares
 Guillermo López-Anglada
 Anne Lord
+Alex LordThorsen
 Tom Loredo
 Justin Love
 Ned Jackson Lovely
diff --git a/Misc/NEWS b/Misc/NEWS
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -10,6 +10,9 @@
 Library
 -------
 
+- Issue #16864: sqlite3.Cursor.lastrowid now supports REPLACE statement.
+  Initial patch by Alex LordThorsen.
+
 - Issue #26386: Fixed ttk.TreeView selection operations with item id's
   containing spaces.
 
diff --git a/Modules/_sqlite/cursor.c b/Modules/_sqlite/cursor.c
--- a/Modules/_sqlite/cursor.c
+++ b/Modules/_sqlite/cursor.c
@@ -698,7 +698,9 @@
         }
 
         Py_DECREF(self->lastrowid);
-        if (!multiple && statement_type == STATEMENT_INSERT) {
+        if (!multiple &&
+            /* REPLACE is an alias for INSERT OR REPLACE */
+            (statement_type == STATEMENT_INSERT || statement_type == STATEMENT_REPLACE)) {
             sqlite_int64 lastrowid;
             Py_BEGIN_ALLOW_THREADS
             lastrowid = sqlite3_last_insert_rowid(self->connection->db);

-- 
Repository URL: https://hg.python.org/cpython


More information about the Python-checkins mailing list