On May 20, 2008, at 1:21 PM, Bram de Jong wrote:
> Hello all,
>
>
> I have found a bug which happens in both FTS2 and FTS3.
>
> The bug happens when a trigger updates an FTS table: the insert ID
> gets trashed:
>
> <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
> create table one
> (
> id integer not null primary key autoincrement,
> value text not null default ''
> );
>
> create virtual table search using fts2(one_id, data);
>
> create trigger sound_insert after insert on one for each row
> begin
> insert into search (one_id, data) values (new.id, new.value);
> end;
>
> create trigger one_update after update on one for each row
> begin
> update search set data = random() where search.one_id=new.id;
> end;
>
> insert into one (value) values ("hello1");
> select last_insert_rowid(); -- returns 1
> insert into one (value) values ("hello2");
> select last_insert_rowid(); -- returns 2
> update one set value="hello3" where id=1;
> select last_insert_rowid(); -- returns 3, but should return 2
> <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
>
> My scheme is a bit more complex (more triggers and more tables), but
> this is as far as I could reduce it.
> Notice that if the search table gets updated via a trigger NOT
> installed on the "one" table, the same problem occurs.
>
> I found the problem described here:
> http://www.mail-archive.com/[email protected]/msg30552.html
> but there was no mention of a fix, nor was there a simple example
> which reproduced the error.
I haven't actually tried to prove it, but it seems likely that this is
because the FTS implementation is doing some INSERTs into shadow
tables when you preform your UPDATE. SQLite in general and virtual
tables in particular tend to be recursive.
The original specification for sqlite3_last_insert_rowid() was that it
"returned the rowid of the most recent INSERT". We later modified the
definition to take triggers into account. So that now we say that
"sqlite3_last_insert_rowid() returns the rowid in the most recent
INSERT from the same or higher level trigger context". Do we need to
further complicate the specification to include virtual tables as
well? What about application-defined functions that invoke SQLite
recursively? Suppose you create an application-defined function named
"eval" that passes its argument back to sqltie3_exec(). Then you do
something like:
INSERT INTO t1 VALUES('INSERT INTO t2 VALUES(5)');
SELECT eval(x) FROM t1;
Should the last-insert-rowid be updated by the INSERT statement this
is invoked recursively by the SELECT statement? If not, how do we
define in a easy-to-understand sentence or two exactly how
sqlite3_last_insert_rowid() really works?
In Bram's case, he was surprised that the last-insert-rowid changed
because he is not thinking about how FTS works behind the scenes. And
this is reasonable. There is a lot of magic in FTS that programmers
are not expected to understand. So it is reasonable for INSERTs done
internally by FTS to not change the last-insert-rowid. But one can
easily imagine other virtual tables that are more transparent and in
which the programmer would expect the last-insert-rowid to be
updated. How do you specify when the last-insert-rowid is updated and
when it is not?
So it is not at all clear to me whether this behavior is a bug or a
feature. SQLite is doing what the documentation says it ought to do.
The question is, should the specification of what SQLite ought to do
change in order to be less surprising to programmers? And if so, what
would that new specification be?
D. Richard Hipp
[EMAIL PROTECTED]
_______________________________________________
sqlite-users mailing list
[email protected]
http://sqlite.org:8080/cgi-bin/mailman/listinfo/sqlite-users