How about calling sqlite3_update_hook()? You will be notified about all UPDATE, INSERT and DELETE operations as they occur, with the database, table and rowid affected and in the thread executing the statement.
If you register a well-behaved function (i.e. that calls the previously registered function) these hooks may even be layered... Von: Mikael [mailto:mikael.tr...@gmail.com] Gesendet: Dienstag, 07. Mai 2013 14:15 An: Richard Hipp; Simon Slavin; Hick Gunter; James K. Lowden; General Discussion of SQLite Database Betreff: Re: [sqlite] How do sqlite3_reset_last_insert_rowid() or functionalequivalent? Hi, Thanks for your feedback, James. A generalized way of getting if an ID was inserted on the last performed query and if so which, is of value for instance when inserting a row into a table with an AUTOINCREMENT key e.g. CREATE TABLE t ( id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, d TEXT ); and then inserting into it, e.g. "INSERT INTO t (d) VALUES (\"a\");" => inserted id: 1 "INSERT INTO t (d) VALUES (\"a\");" => inserted id: 2 "INSERT INTO t (d) VALUES (\"b\");" => inserted id: 3 "INSERT INTO t (d) VALUES (\"b\");" => inserted id: 4 "INSERT INTO t (d) VALUES (\"c\");" => inserted id: 5 This functionality makes a lot of sense in at least certain SQLite bindings. In the places where it's not strictly required, it will still provide clarity which is valuable in debug, and convenience from being dynamic, please see the example use ~15 rows below for this - So what I'm looking for is a general mechanism for deriving the ID inserted for a query. E.g.: "SELECT a FROM b" => none "UPDATE b SET a = c" => none "INSERT IGNORE INTO b (a) VALUES (c)" and the ID was already in there => none "INSERT IGNORE INTO b (a) VALUES (c)" and the ID was not already in there => the ID of the inserted row "INSERT INTO b (a) VALUES (c)" => the ID of the inserted row Thanks to this, a SQLite binding can be achieved which dynamically/*automatically* detects not only if it was a readonly or non-readonly query, but also within the non-readonly query if it was an update or insert, and thus a generalized query mechanism can be devised that behaves like: SELECT query => The query results UPDATE query => The number of rows updated INSERT query => The ID of the row inserted, or none (by null/false/0/etc.) This is to create a general abstraction for this purpose. Indeed SQLite performs queries, well, at the level of query and, the meaningful work you do with SQLite is at the granularity of a query, so it appears reasonable to me that there would be a mechanism using which you could retrieve the ID of the row inserted by a particular query. A generalized "rows changed by this query" abstraction can be implemented as of today, using sqlite3_changes which returns the number of changed rows in the *last performed query*, the error reporting (as to check sqlite3_changes was set on the last query) and possibly secondarily by stmt_readonly . The problem with checking the ID of the last inserted row is that the abstraction for checking it cannot reasonably know that a query is an insert; Essentially doing a string match for "INSERT " in the query executed would be a leaky abstraction. Getting a copy of SQLite's SQL parser's data could be something, but then - this is a bit beyond my current SQLite skills - aren't there mechanisms to make INSERT:s indirectly in SQLite, like through a database-stored procedure or alike? That would make any abstraction like this leak, because it wouldn't know if an INSERT was made during a query, and that knowledge is required as to know if sqlite3_last_insert_rowid regards the last inserted ID or not. And to illustrate how sqlite3_changes and sqlite3_last_insert_rowid does not deliver for automatic query ID retrieval: Using these two, let's define an attempt at a general mechanism for this, in pseudocode: var last_rowId_on_last_query = 0; function query(query) { lock_mutex(); sqlite_perform_query(query); var last_rowId = sqlite_last_rowid(); var id_of_this_row = (last_rowId != last_rowId_on_last_query) ? last_rowId : null; last_rowId_on_last_query = last_rowId; unlock_mutex(); return id_of_this_row; } Now, let's set up these two tables CREATE TABLE t1 ( id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, d TEXT ); CREATE TABLE t2 ( id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, d TEXT ); and now make some inserts with it! The use of query() above is implied here. "INSERT INTO t1 (d) VALUES (\"a\");" => 1 - Correct! "INSERT INTO t1 (d) VALUES (\"a\");" => 2 - Correct! "INSERT INTO t2 (d) VALUES (\"a\");" => 1 - Correct! "INSERT INTO t2 (d) VALUES (\"a\");" => 2 - Correct! "INSERT INTO t2 (d) VALUES (\"a\");" => 3 - Correct! "INSERT INTO t1 (d) VALUES (\"a\");" => null - Error, abstraction leak, ouch! All of this leakiness would be undone if before a query, the SQLite user could reset the sqlite3_last_insert_rowid . By that, the user can just check the sqlite3_last_insert_rowid right after the query, and by that know that that was . It may be a bit too simplistic if a query inserted several ID:s as you pointed out, though at least it's general unlike the present solution, and can be made to fit any usecase at least I have in reach, as in SQLite any INSERT operation can be performed one row per query with OK-to-great performance. Introduction of a sqlite3_reset_last_insert_rowid would be complimenting the current sqlite_int64 sqlite3_last_insert_rowid at sqlite3.c row 114023-114028: /* ** Return the ROWID of the most recent insert */ SQLITE_API sqlite_int64 sqlite3_last_insert_rowid(sqlite3 *db){ return db->lastRowid; } with the similar SQLITE_API void sqlite3_reset_last_insert_rowid(sqlite3 *db){ db->lastRowid = 0; } and then making it export properly. The reason I address you on this list directly with this is because it appears to be of use for SQLite bindings as far as I can see. I agree that keeping the API minimal is a top priority. Though, for instance exporting this as a SQL procedure that could be invoked by preparing "CALL reset_last_insert_rowid();" and then invoking it, wouldn't that be a bit too costly to do on *every* query however small in a particular binding? If you see any other way to solve this with good performance, please feel free to share, I'm just looking for a general way of getting if the last query inserted an ID and if so which, it can be implemented any way as long as it performs so good it can be included in a general query mechanism in a binding. Thanks, Mikael 2013/5/7 James K. Lowden <jklow...@schemamania.org<mailto:jklow...@schemamania.org>> On Mon, 6 May 2013 20:55:01 +0300 Mikael <mikael.tr...@gmail.com<mailto:mikael.tr...@gmail.com>> wrote: > Currently in the absence of a sqlite3_reset_last_insert_rowid(), the > closest you can do to figure out what ID was actually inserted by the > most recent SQLite query is: > > * Lock mutex > * Get sqlite*'s last insert row ID > * Perform the query > * Get number of changed rows > * Get sqlite*'s last insert row ID > * Unlock mutex I don't understand. The process doing the insert presumably knows which data it inserted. Why not turn around and SELECT the ids for the inserted values? No mutex and no guesswork. Your process seems to imply that the the inserted values don't constitute a key, or that you want to compute the row IDs for performance. Those don't strike me as sufficient reason to perturb the API. --jkl _______________________________________________ sqlite-users mailing list sqlite-users@sqlite.org<mailto:sqlite-users@sqlite.org> http://sqlite.org:8080/cgi-bin/mailman/listinfo/sqlite-users ________________________________ Gunter Hick Software Engineer Scientific Games International GmbH Klitschgasse 2 - 4, A - 1130 Vienna, Austria FN 157284 a, HG Wien Tel: +43 1 80100 0 E-Mail: h...@scigames.at This e-mail is confidential and may well also be legally privileged. If you have received it in error, you are on notice as to its status and accordingly please notify us immediately by reply e-mail and then delete this message from your system. Please do not copy it or use it for any purposes, or disclose its contents to any person as to do so could be a breach of confidence. Thank you for your cooperation. _______________________________________________ sqlite-users mailing list sqlite-users@sqlite.org http://sqlite.org:8080/cgi-bin/mailman/listinfo/sqlite-users