/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 20:56:19 UTC
  • Revision ID: edam@waxworlds.org-20100729205619-a9yo4uzu647nvnsj
- renamed database to connection to better identify what it is (would database_connection be better though?)
- moved basic_statement and basic_transaction to sqlite::detail
- made sqlite::threadsafe() return the threading mode int, not a bool
- renamed row::index() to row_number() so it isn't confused with column index
- added typedef for deferred_transaction
- added early rollback method to transaction_guard
- allowed transaction_guard::~transaction_guard() to throw exceptions, since when it needs to, we're really screwed anyway
- bugfix: query::reset() didn't reset the internal row counter
- added query::num_results()
- added docs/design-notes
- reimplemented query::iterator so that increment() (which performs a step() on the query) now caches the returned row to be returned during dereference() (previously it stashed details and returned new row!?)
- bugfix: resetting active queries during rollbacks would hang!

Show diffs side-by-side

added added

removed removed

 
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