As various people search for application and/or SQLite bugs
related to multiple threads and BEGIN, let me try to aid the
effort by better describing exactly what BEGIN does and 
suggesting some debugging tricks.

Realize that BEGIN does not actually create any file locks
or check to see if any file locks already exist, nor
interact in any other way with the filesystem.  File locks
are only created by SELECT, UPDATE, INSERT, and DELETE
statements.  (OK, also CREATE and DROP statements, but 
let's ignore those for now for simplicity.  Presumably 
the schema is fixed at the point where the problems are
occuring.)  All BEGIN does is to set a flag that says
"do not automatically perform a COMMIT after each write
to the database".  This is the autoCommit flag that I
mentioned in a prior email.  autoCommit is a boolean
member of the sqlite3 structure.  A lock is acquired
at the beginning of each UPDATE, INSERT, or DELETE
if it does not already exists.  After each UPDATE,
INSERT, or DELETE, sqlite checks the value of the
autoCommit flag, and if it is true it automatically
does a COMMIT.  A read-lock is acquired before each
SELECT if it does not already exists, and after the
SELECT is done, the read-lock is dropped if autoCommit
is true.

So the BEGIN instruction does not do anything with the
filesystem.  It does not interact in any way with the
operating system or with other database connections.
All BEGIN does is clear the autoCommit flag.  So it is
hard to imagine how having other threads could possibly
effect its behavior.

At any time, you can determine the value of the autoCommit
flag using the sqlite3_get_autocommit() API.  See

  http://www.sqlite.org/capi3ref.html#sqlite3_get_autocommit

I suggest that people who are getting back unexpected
"cannot start a transaction within a transaction" errors
should use the sqlite3_get_autocommit() API in some printf()s
to trace the status of the autocommit flag within their
application.  Prior to running BEGIN, it should always
be the case that sqlite3_get_autocommit() returns TRUE.
If sqlite3_get_autocommit() returns FALSE, then the BEGIN
that follows will give the "cannot start..." error.

I suspect what is happening is that some prior COMMIT
or ROLLBACK is not setting the autoCommit flag back to
TRUE.  This might be because the COMMIT or ROLLBACK
failed.  Or, there could be some kind of bug in SQLite
that is causing the autoCommit flag to not be set
correctly.  I suspect the former, but am open to evidence
pointing to the latter.  It might be useful to use the
sqlite3_get_autocommit() function to print out the value
of the autoCommit flag after each COMMIT and ROLLBACK is
executed.  This might help to isolate the problem.

--
D. Richard Hipp   <[EMAIL PROTECTED]>

Reply via email to