aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/main.c20
-rw-r--r--src/sqlite.h.in19
-rw-r--r--src/sqliteInt.h4
-rw-r--r--src/tclsqlite.c73
-rw-r--r--src/vdbe.c9
5 files changed, 112 insertions, 13 deletions
diff --git a/src/main.c b/src/main.c
index 6386495e2..2b4a396ca 100644
--- a/src/main.c
+++ b/src/main.c
@@ -14,7 +14,7 @@
** other files are for internal use by SQLite and should not be
** accessed by users of the library.
**
-** $Id: main.c,v 1.144 2003/12/06 21:43:56 drh Exp $
+** $Id: main.c,v 1.145 2004/01/15 02:44:03 drh Exp $
*/
#include "sqliteInt.h"
#include "os.h"
@@ -976,6 +976,24 @@ void *sqlite_trace(sqlite *db, void (*xTrace)(void*,const char*), void *pArg){
return pOld;
}
+/*** EXPERIMENTAL ***
+**
+** Register a function to be invoked when a transaction comments.
+** If either function returns non-zero, then the commit becomes a
+** rollback.
+*/
+void *sqlite_commit_hook(
+ sqlite *db, /* Attach the hook to this database */
+ int (*xCallback)(void*), /* Function to invoke on each commit */
+ void *pArg /* Argument to the function */
+){
+ void *pOld = db->pCommitArg;
+ db->xCommitCallback = xCallback;
+ db->pCommitArg = pArg;
+ return pOld;
+}
+
+
/*
** This routine is called to create a connection to a database BTree
** driver. If zFilename is the name of a file, then that file is
diff --git a/src/sqlite.h.in b/src/sqlite.h.in
index 6f8712145..e493a13fe 100644
--- a/src/sqlite.h.in
+++ b/src/sqlite.h.in
@@ -12,7 +12,7 @@
** This header file defines the interface that the SQLite library
** presents to client programs.
**
-** @(#) $Id: sqlite.h.in,v 1.53 2003/10/18 09:37:26 danielk1977 Exp $
+** @(#) $Id: sqlite.h.in,v 1.54 2004/01/15 02:44:03 drh Exp $
*/
#ifndef _SQLITE_H_
#define _SQLITE_H_
@@ -753,9 +753,26 @@ int sqlite_bind(sqlite_vm*, int idx, const char *value, int len, int copy);
** query is immediately terminated and any database changes rolled back. If the
** query was part of a larger transaction, then the transaction is not rolled
** back and remains active. The sqlite_exec() call returns SQLITE_ABORT.
+**
+******* THIS IS AN EXPERIMENTAL API AND IS SUBJECT TO CHANGE ******
*/
void sqlite_progress_handler(sqlite*, int, int(*)(void*), void*);
+/*
+** Register a callback function to be invoked whenever a new transaction
+** is committed. The pArg argument is passed through to the callback.
+** callback. If the callback function returns non-zero, then the commit
+** is converted into a rollback.
+**
+** If another function was previously registered, its pArg value is returned.
+** Otherwise NULL is returned.
+**
+** Registering a NULL function disables the callback.
+**
+******* THIS IS AN EXPERIMENTAL API AND IS SUBJECT TO CHANGE ******
+*/
+void *sqlite_commit_hook(sqlite*, int(*)(void*), void*);
+
#ifdef __cplusplus
} /* End of the 'extern "C"' block */
#endif
diff --git a/src/sqliteInt.h b/src/sqliteInt.h
index c90190af2..989478607 100644
--- a/src/sqliteInt.h
+++ b/src/sqliteInt.h
@@ -11,7 +11,7 @@
*************************************************************************
** Internal interface definitions for SQLite.
**
-** @(#) $Id: sqliteInt.h,v 1.207 2004/01/07 03:04:27 drh Exp $
+** @(#) $Id: sqliteInt.h,v 1.208 2004/01/15 02:44:03 drh Exp $
*/
#include "config.h"
#include "sqlite.h"
@@ -322,6 +322,8 @@ struct sqlite {
int nTable; /* Number of tables in the database */
void *pBusyArg; /* 1st Argument to the busy callback */
int (*xBusyCallback)(void *,const char*,int); /* The busy callback */
+ void *pCommitArg; /* Argument to xCommitCallback() */
+ int (*xCommitCallback)(void*);/* Invoked at every commit. */
Hash aFunc; /* All functions that can be in SQL exprs */
int lastRowid; /* ROWID of most recent insert */
int priorNewRowid; /* Last randomly generated ROWID */
diff --git a/src/tclsqlite.c b/src/tclsqlite.c
index c2f4cfd49..70706306a 100644
--- a/src/tclsqlite.c
+++ b/src/tclsqlite.c
@@ -11,7 +11,7 @@
*************************************************************************
** A TCL Interface to SQLite
**
-** $Id: tclsqlite.c,v 1.53 2003/12/19 12:32:46 drh Exp $
+** $Id: tclsqlite.c,v 1.54 2004/01/15 02:44:03 drh Exp $
*/
#ifndef NO_TCL /* Omit this whole file if TCL is unavailable */
@@ -51,6 +51,7 @@ struct SqliteDb {
sqlite *db; /* The "real" database structure */
Tcl_Interp *interp; /* The interpreter used for this database */
char *zBusy; /* The busy callback routine */
+ char *zCommit; /* The commit hook callback routine */
char *zTrace; /* The trace callback routine */
char *zProgress; /* The progress callback routine */
char *zAuth; /* The authorization callback routine */
@@ -358,6 +359,23 @@ static void DbTraceHandler(void *cd, const char *zSql){
}
/*
+** This routine is called when a transaction is committed. The
+** TCL script in pDb->zCommit is executed. If it returns non-zero or
+** if it throws an exception, the transaction is rolled back instead
+** of being committed.
+*/
+static int DbCommitHandler(void *cd){
+ SqliteDb *pDb = (SqliteDb*)cd;
+ int rc;
+
+ rc = Tcl_Eval(pDb->interp, pDb->zCommit);
+ if( rc!=TCL_OK || atoi(Tcl_GetStringResult(pDb->interp)) ){
+ return 1;
+ }
+ return 0;
+}
+
+/*
** This routine is called to evaluate an SQL function implemented
** using TCL script.
*/
@@ -470,17 +488,17 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
int choice;
static const char *DB_strs[] = {
"authorizer", "busy", "changes",
- "close", "complete", "errorcode",
- "eval", "function", "last_insert_rowid",
- "onecolumn", "timeout", "trace",
- "progress", 0
+ "close", "commit_hook", "complete",
+ "errorcode", "eval", "function",
+ "last_insert_rowid", "onecolumn", "progress",
+ "timeout", "trace", 0
};
enum DB_enum {
DB_AUTHORIZER, DB_BUSY, DB_CHANGES,
- DB_CLOSE, DB_COMPLETE, DB_ERRORCODE,
- DB_EVAL, DB_FUNCTION, DB_LAST_INSERT_ROWID,
- DB_ONECOLUMN, DB_TIMEOUT, DB_TRACE,
- DB_PROGRESS
+ DB_CLOSE, DB_COMMIT_HOOK, DB_COMPLETE,
+ DB_ERRORCODE, DB_EVAL, DB_FUNCTION,
+ DB_LAST_INSERT_ROWID, DB_ONECOLUMN, DB_PROGRESS,
+ DB_TIMEOUT, DB_TRACE,
};
if( objc<2 ){
@@ -649,6 +667,43 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
break;
}
+ /* $db commit_hook ?CALLBACK?
+ **
+ ** Invoke the given callback just before committing every SQL transaction.
+ ** If the callback throws an exception or returns non-zero, then the
+ ** transaction is aborted. If CALLBACK is an empty string, the callback
+ ** is disabled.
+ */
+ case DB_COMMIT_HOOK: {
+ if( objc>3 ){
+ Tcl_WrongNumArgs(interp, 2, objv, "?CALLBACK?");
+ }else if( objc==2 ){
+ if( pDb->zCommit ){
+ Tcl_AppendResult(interp, pDb->zCommit, 0);
+ }
+ }else{
+ char *zCommit;
+ int len;
+ if( pDb->zCommit ){
+ Tcl_Free(pDb->zCommit);
+ }
+ zCommit = Tcl_GetStringFromObj(objv[2], &len);
+ if( zCommit && len>0 ){
+ pDb->zCommit = Tcl_Alloc( len + 1 );
+ strcpy(pDb->zCommit, zCommit);
+ }else{
+ pDb->zCommit = 0;
+ }
+ if( pDb->zCommit ){
+ pDb->interp = interp;
+ sqlite_commit_hook(pDb->db, DbCommitHandler, pDb);
+ }else{
+ sqlite_commit_hook(pDb->db, 0, 0);
+ }
+ }
+ break;
+ }
+
/* $db complete SQL
**
** Return TRUE if SQL is a complete SQL statement. Return FALSE if
diff --git a/src/vdbe.c b/src/vdbe.c
index 505ff5fe3..64c8fe0fb 100644
--- a/src/vdbe.c
+++ b/src/vdbe.c
@@ -43,7 +43,7 @@
** in this file for details. If in doubt, do not deviate from existing
** commenting and indentation practices when changing or adding code.
**
-** $Id: vdbe.c,v 1.250 2004/01/14 21:59:23 drh Exp $
+** $Id: vdbe.c,v 1.251 2004/01/15 02:44:03 drh Exp $
*/
#include "sqliteInt.h"
#include "os.h"
@@ -2245,6 +2245,13 @@ case OP_Transaction: {
*/
case OP_Commit: {
int i;
+ if( db->xCommitCallback!=0 ){
+ if( sqliteSafetyOff(db) ) goto abort_due_to_misuse;
+ if( db->xCommitCallback(db->pCommitArg)!=0 ){
+ rc = SQLITE_CONSTRAINT;
+ }
+ if( sqliteSafetyOn(db) ) goto abort_due_to_misuse;
+ }
for(i=0; rc==SQLITE_OK && i<db->nDb; i++){
if( db->aDb[i].inTrans ){
rc = sqliteBtreeCommit(db->aDb[i].pBt);