Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit e0b70cd

Browse files
committed
Issue #16864: Cursor.lastrowid now supports REPLACE statement
Initial patch by Alex LordThorsen.
1 parent 34f12d7 commit e0b70cd

6 files changed

Lines changed: 66 additions & 5 deletions

File tree

Doc/library/sqlite3.rst

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -629,9 +629,16 @@ Cursor Objects
629629
.. attribute:: lastrowid
630630

631631
This read-only attribute provides the rowid of the last modified row. It is
632-
only set if you issued an ``INSERT`` statement using the :meth:`execute`
633-
method. For operations other than ``INSERT`` or when :meth:`executemany` is
634-
called, :attr:`lastrowid` is set to :const:`None`.
632+
only set if you issued an ``INSERT`` or a ``REPLACE`` statement using the
633+
:meth:`execute` method. For operations other than ``INSERT`` or
634+
``REPLACE`` or when :meth:`executemany` is called, :attr:`lastrowid` is
635+
set to :const:`None`.
636+
637+
If the ``INSERT`` or ``REPLACE`` statement failed to insert the previous
638+
successful rowid is returned.
639+
640+
.. versionchanged:: 3.6
641+
Added support for the ``REPLACE`` statement.
635642

636643
.. attribute:: description
637644

Doc/whatsnew/3.6.rst

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -339,6 +339,13 @@ you may now specify file paths on top of directories (e.g. zip files).
339339
(Contributed by Wolfgang Langner in :issue:`26587`).
340340

341341

342+
sqlite3
343+
-------
344+
345+
* :attr:`sqlite3.Cursor.lastrowid` now supports the ``REPLACE`` statement.
346+
(Contributed by Alex LordThorsen in :issue:`16864`.)
347+
348+
342349
socketserver
343350
------------
344351

Lib/sqlite3/test/dbapi.py

Lines changed: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -188,7 +188,10 @@ class CursorTests(unittest.TestCase):
188188
def setUp(self):
189189
self.cx = sqlite.connect(":memory:")
190190
self.cu = self.cx.cursor()
191-
self.cu.execute("create table test(id integer primary key, name text, income number)")
191+
self.cu.execute(
192+
"create table test(id integer primary key, name text, "
193+
"income number, unique_test text unique)"
194+
)
192195
self.cu.execute("insert into test(name) values (?)", ("foo",))
193196

194197
def tearDown(self):
@@ -462,6 +465,44 @@ class Foo: pass
462465
with self.assertRaises(TypeError):
463466
cur = sqlite.Cursor(foo)
464467

468+
def CheckLastRowIDOnReplace(self):
469+
"""
470+
INSERT OR REPLACE and REPLACE INTO should produce the same behavior.
471+
"""
472+
sql = '{} INTO test(id, unique_test) VALUES (?, ?)'
473+
for statement in ('INSERT OR REPLACE', 'REPLACE'):
474+
with self.subTest(statement=statement):
475+
self.cu.execute(sql.format(statement), (1, 'foo'))
476+
self.assertEqual(self.cu.lastrowid, 1)
477+
478+
def CheckLastRowIDOnIgnore(self):
479+
self.cu.execute(
480+
"insert or ignore into test(unique_test) values (?)",
481+
('test',))
482+
self.assertEqual(self.cu.lastrowid, 2)
483+
self.cu.execute(
484+
"insert or ignore into test(unique_test) values (?)",
485+
('test',))
486+
self.assertEqual(self.cu.lastrowid, 2)
487+
488+
def CheckLastRowIDInsertOR(self):
489+
results = []
490+
for statement in ('FAIL', 'ABORT', 'ROLLBACK'):
491+
sql = 'INSERT OR {} INTO test(unique_test) VALUES (?)'
492+
with self.subTest(statement='INSERT OR {}'.format(statement)):
493+
self.cu.execute(sql.format(statement), (statement,))
494+
results.append((statement, self.cu.lastrowid))
495+
with self.assertRaises(sqlite.IntegrityError):
496+
self.cu.execute(sql.format(statement), (statement,))
497+
results.append((statement, self.cu.lastrowid))
498+
expected = [
499+
('FAIL', 2), ('FAIL', 2),
500+
('ABORT', 3), ('ABORT', 3),
501+
('ROLLBACK', 4), ('ROLLBACK', 4),
502+
]
503+
self.assertEqual(results, expected)
504+
505+
465506
@unittest.skipUnless(threading, 'This test requires threading.')
466507
class ThreadTests(unittest.TestCase):
467508
def setUp(self):

Misc/ACKS

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -895,6 +895,7 @@ Martin von Löwis
895895
Hugo Lopes Tavares
896896
Guillermo López-Anglada
897897
Anne Lord
898+
Alex LordThorsen
898899
Tom Loredo
899900
Justin Love
900901
Ned Jackson Lovely

Misc/NEWS

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@ What's New in Python 3.6.0 alpha 3
1010
Library
1111
-------
1212

13+
- Issue #16864: sqlite3.Cursor.lastrowid now supports REPLACE statement.
14+
Initial patch by Alex LordThorsen.
15+
1316
- Issue #26386: Fixed ttk.TreeView selection operations with item id's
1417
containing spaces.
1518

Modules/_sqlite/cursor.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -698,7 +698,9 @@ PyObject* _pysqlite_query_execute(pysqlite_Cursor* self, int multiple, PyObject*
698698
}
699699

700700
Py_DECREF(self->lastrowid);
701-
if (!multiple && statement_type == STATEMENT_INSERT) {
701+
if (!multiple &&
702+
/* REPLACE is an alias for INSERT OR REPLACE */
703+
(statement_type == STATEMENT_INSERT || statement_type == STATEMENT_REPLACE)) {
702704
sqlite_int64 lastrowid;
703705
Py_BEGIN_ALLOW_THREADS
704706
lastrowid = sqlite3_last_insert_rowid(self->connection->db);

0 commit comments

Comments
 (0)