Differences From:
File
src/db.c
part of check-in
[29bc8da1d9]
- Added diff-command and gdiff-command to the valid settings
by
jnc on
2007-10-10 03:39:04.
[view]
To:
File
src/db.c
part of check-in
[d5e7891b07]
- Add a more advanced commit-hook mechanism that allows us to
specify multiple procedures in a particular order prior to commit.
Continuing work toward getting tickets going.
by
drh on
2007-11-18 20:48:07.
[view]
@@ -78,20 +78,49 @@
}
static int nBegin = 0; /* Nesting depth of BEGIN */
static int doRollback = 0; /* True to force a rollback */
+static int nCommitHook = 0; /* Number of commit hooks */
+static struct sCommitHook {
+ int (*xHook)(void); /* Functions to call at db_end_transaction() */
+ int sequence; /* Call functions in sequence order */
+} aHook[5];
+
+/*
+** This routine is called by the SQLite commit-hook mechanism
+** just prior to each omit. All this routine does is verify
+** that nBegin really is zero. That insures that transactions
+** cannot commit by any means other than by calling db_end_transaction()
+** below.
+**
+** This is just a safety and sanity check.
+*/
+static int db_verify_at_commit(void *notUsed){
+ if( nBegin ){
+ fossil_panic("illegal commit attempt");
+ return 1;
+ }
+ return 0;
+}
/*
** Begin and end a nested transaction
*/
void db_begin_transaction(void){
- if( nBegin==0 ) db_multi_exec("BEGIN");
+ if( nBegin==0 ){
+ db_multi_exec("BEGIN");
+ sqlite3_commit_hook(g.db, db_verify_at_commit, 0);
+ }
nBegin++;
}
void db_end_transaction(int rollbackFlag){
if( rollbackFlag ) doRollback = 1;
nBegin--;
if( nBegin==0 ){
+ int i;
+ for(i=0; doRollback==0 && i<nCommitHook; i++){
+ doRollback |= aHook[i].xHook();
+ }
db_multi_exec(doRollback ? "ROLLBACK" : "COMMIT");
doRollback = 0;
}
}
@@ -99,8 +128,37 @@
if( nBegin ){
sqlite3_exec(g.db, "ROLLBACK", 0, 0, 0);
}
nBegin = 0;
+}
+
+/*
+** Install a commit hook. Hooks are installed in sequence order.
+** It is an error to install the same commit hook more than once.
+**
+** Each commit hook is called (in order of accending sequence) at
+** each commit operation. If any commit hook returns non-zero,
+** the subsequence commit hooks are omitted and the transaction
+** rolls back rather than commit. It is the responsibility of the
+** hooks themselves to issue any error messages.
+*/
+void db_commit_hook(int (*x)(void), int sequence){
+ int i;
+ assert( nCommitHook < sizeof(aHook)/sizeof(aHook[1]) );
+ for(i=0; i<nCommitHook; i++){
+ assert( x!=aHook[i].xHook );
+ if( aHook[i].sequence>sequence ){
+ int s = sequence;
+ int (*xS)(void) = x;
+ sequence = aHook[i].sequence;
+ x = aHook[i].xHook;
+ aHook[i].sequence = s;
+ aHook[i].xHook = xS;
+ }
+ }
+ aHook[nCommitHook].sequence = sequence;
+ aHook[nCommitHook].xHook = x;
+ nCommitHook++;
}
/*
** Prepare or reprepare the sqlite3 statement from the raw SQL text.