/sqlite3cc

To get this branch, use:
bzr branch http://bzr.ed.am/sqlite3cc

« back to all changes in this revision

Viewing changes to docs/design-notes

  • Committer: edam
  • Date: 2010-07-29 06:28:53 UTC
  • Revision ID: edam@waxworlds.org-20100729062853-4i2fec52m86mh724
- made basic_statement::step() protected, for use by query and command only
- moved basic_statement::operator<<() to command and query instead; one needs to accept sqlite::exec, the other doesn't
- added tests for query::operator<<()
- added code to invlaidate in-progress queries during any transaction rollbacks (currently segfaults in basic_statement::finalize())
- added new sqlite_error constructor that obtains a full error message
- implemented database::database_mutex_guard class
- swapped command's step mutex in favour of the database mutex

Show diffs side-by-side

added added

removed removed

Lines of Context:
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