I did the experiment.  I used two Terminal windows accessing the same database. 
 It's not quite the right experiment because I can't figure out how to make the 
shell tool stop in the middle of a SELECT.  So instead I used a transaction to 
keep the database locked between two SELECT commands.

Here's the setup:

SQLite version 3.8.10.2 2015-05-20 18:17:19
Enter ".help" for usage hints.
sqlite> CREATE TABLE t(c INT);
sqlite> INSERT INTO t (c) VALUES (1),(2),(3),(4),(5);
sqlite> SELECT * FROM t;
1
2
3
4
5
sqlite> 

First, an attempt in default journaling mode:

In window A:

sqlite> PRAGMA journal_mode;
delete
sqlite> BEGIN;
sqlite> SELECT * FROM t;
1
2
3
4
5

In window B:

sqlite> INSERT INTO t (c) VALUES (6);
Error: database is locked
sqlite> ALTER TABLE t ADD COLUMN y TEXT;
Error: database is locked

So it won't let you do INSERT or ADD COLUMN because the database is locked, as 
expected.  Now try it in WAL mode.  (To my surprise I had to .quit and reopen 
in window B for it to register that the journal mode had changed.  Can anyone 
tell me why ?)

In window A:

sqlite> END;
sqlite> PRAGMA journal_mode = WAL;
wal
sqlite> PRAGMA journal_mode;
wal
sqlite> BEGIN;
sqlite> SELECT * FROM t;
1
2
3
4
5

In window B (after .quit and reopen):

sqlite> PRAGMA journal_mode;
wal
sqlite> INSERT INTO t (c) VALUES (6);
sqlite> ALTER TABLE t ADD COLUMN y TEXT DEFAULT 'unchanged';
sqlite> SELECT * FROM t;
1|unchanged
2|unchanged
3|unchanged
4|unchanged
5|unchanged
6|unchanged

Back to window A:

sqlite> SELECT * FROM t;
1
2
3
4
5
sqlite> END;
sqlite> SELECT * FROM t;
1|unchanged
2|unchanged
3|unchanged
4|unchanged
5|unchanged
6|unchanged

As expected, ALTER TABLE acts like INSERT: it's a change which requires an 
exclusive lock.  So just as the documentation says, in a normal journal mode 
you can't make a change while the database is locked (which it is during a 
SELECT), and in WAL mode you can make the change but the connection doing the 
SELECT won't see it until it finishes its transaction.

Which gives the grand conclusion I posted earlier: OP does not have to worry 
about this issue.  It can never happen.  Your schema cannot be changed on you 
while you're inside a transaction if you don't intentionally defeat SQLite's 
locking mechanism.

Which is what I'd thought and hoped, since in any scenario where schema can 
change while a SELECT is running (e.g. anywhere a graphical front end to SQLite 
was in use) every programmer would have had to write horrible extra code to 
handle the possibility.

Simon.

Reply via email to