/sqlite3cc

To get this branch, use:
bzr branch http://bzr.ed.am/sqlite3cc
16 by edam
- renamed database to connection to better identify what it is (would database_connection be better though?)
1
2
DESIGN NOTES
3
============
4
5
This file attempts to document the issues, pros and cons of various design
6
decisions that were made during the development of this library
7
8
9
Boost mutexes vs. SQLite mutexes
10
--------------------------------
11
12
- Using boost's mutexes creates an additional dependency on a boost library
13
- With sqlite's mutexes, all statements play well together, even those that do
14
	not explicitly use the database mutex (such as sqlite3 calls made by the
15
	user from outside sqlite3cc)
16
17
18
Invalidating in-progress statements before rollback and commit
19
--------------------------------------------------------------
20
21
The issue is that attempting to execute a ROLLBACK or COMMIT can sometimes
22
result in an error, depending on the state of other statements. Potentially,
23
rollbacks are done by the transaction_guard dtor when unwinding the stack in
24
response to an exception. Therefore, it is essential that they don't fail
25
because of outstanding statements as we cannot throw an additional exception.
26
27
In practice, this issue only happens when queries, specifically, are still "in-
28
progress" (i.e., the previous call to sqlite3_step() for the statement resulted
29
in SQLITE_ROW being returned; before sqlite_step() is called and after
30
sqlite_step() returns SQLITE_DONE, statements are no longer "in-progress"). For
31
commands, there should be no results (SQLITE_ROW should never be returned) so
32
finalising the statement in command::step() is acceptable and guarantees that
33
commands will not be an issue.
34
35
The errors caused:
36
- exec BEGIN, prep/step SELECT (returning row), prep/step on ROLLBACK gives
37
	SQLITE_BUSY "database is locked"
38
- exec BEGIN, exec INSERT, prep/step SELECT (returning row), prep/step
39
	ROLLBACK gives SQLITE_ERROR "SQL statements in progress"
40
41
Possible solution is to reset queries during rollback and commit. This has a
42
danger associated with it that if the application is multi-threaded, we might
43
end up resetting a query from another thread. But then, if you're sharing a
44
database connection between threads and using transactions, you probably need
45
your head looking at. So, there are two ways we can do this:
46
47
1. simply user sqlite3_next_stmt() to get outstanding statements and call
48
	sqlite3_reset() on them
49
	- this is an efficient solution, although not very OO.
50
51
2. keep a map of active (i.e. those for whom step() last returned SQLITE_ROW)
52
	queries in the database (using the sqlite3_stmt pointer as the key) and
53
	iterate through asking queries to reset themselves.
54
	- this is a more OO way of implementing it but has a greater overhead