Reinsert the experimental sqlite_commit_hook() API. (CVS 1179)
FossilOrigin-Name: 72bc84f2f18f6eeb279a4ad670310e85d154f663
This commit is contained in:
parent
751f41217e
commit
aa940eacfe
23
manifest
23
manifest
@ -1,5 +1,5 @@
|
||||
C Fix\scomparisons\sof\sROWID\sagainst\sfloating\spoint\snumbers\sso\sthat\sthey\swork\ncorrectly.\s\sTicket\s#377\sand\s#567.\s(CVS\s1178)
|
||||
D 2004-01-14T21:59:23
|
||||
C Reinsert\sthe\sexperimental\ssqlite_commit_hook()\sAPI.\s(CVS\s1179)
|
||||
D 2004-01-15T02:44:03
|
||||
F Makefile.in 0515ff9218ad8d5a8f6220f0494b8ef94c67013b
|
||||
F Makefile.linux-gcc b86a99c493a5bfb402d1d9178dcdc4bd4b32f906
|
||||
F README f1de682fbbd94899d50aca13d387d1b3fd3be2dd
|
||||
@ -36,7 +36,7 @@ F src/func.c 62cf8fae8147c0301d1c6a4a94fe0a78f7aa5b33
|
||||
F src/hash.c 9b56ef3b291e25168f630d5643a4264ec011c70e
|
||||
F src/hash.h 3247573ab95b9dd90bcca0307a75d9a16da1ccc7
|
||||
F src/insert.c 01f66866f35c986eab4a57373ca689a3255ef2df
|
||||
F src/main.c 3dd3cae00bade294011da5a3cf9ff660a610c545
|
||||
F src/main.c 67af644fa7c1b8bb06032b6a9459d084cf79bb81
|
||||
F src/md5.c fe4f9c9c6f71dfc26af8da63e4d04489b1430565
|
||||
F src/os.c 681ec36217bc7c795d55d9a63ff79a8614ddee8c
|
||||
F src/os.h 257c9aef1567bb20c8b767fc27fe3ee7d89104e0
|
||||
@ -48,10 +48,10 @@ F src/printf.c 292a7bfc5a815cb6465e32b2d5c9fe9bd43b27f0
|
||||
F src/random.c 19e8e00fe0df32a742f115773f57651be327cabe
|
||||
F src/select.c 2712bd4d311ebe7dbf8fd7596a809042657db85f
|
||||
F src/shell.c 3b067edc098c45caca164bcad1fa79192c3ec5ae
|
||||
F src/sqlite.h.in e6cfff01fafc8a82ce82cd8c932af421dc9adb54
|
||||
F src/sqliteInt.h d9f2391451ae9636eb447dfa4dc35b70bfa3759d
|
||||
F src/sqlite.h.in c70d8533cd5a5ae8af580597dbc726693ef82de9
|
||||
F src/sqliteInt.h 99df38d3c16cc727030c218a3fc61de08c071d08
|
||||
F src/table.c d845cb101b5afc1f7fea083c99e3d2fa7998d895
|
||||
F src/tclsqlite.c dcd18d1f0d51ac4863d1f9059f614f903bc1fffe
|
||||
F src/tclsqlite.c 85810fc4a850e2178d71aa5efe576dcd331db596
|
||||
F src/test1.c e8652055d04d241d4fb437b5c33ff07d9f13b4b4
|
||||
F src/test2.c 5014337d8576b731cce5b5a14bec4f0daf432700
|
||||
F src/test3.c 30985ebdfaf3ee1462a9b0652d3efbdc8d9798f5
|
||||
@ -61,7 +61,7 @@ F src/trigger.c ce83e017b407d046e909d05373d7f8ee70f9f7f9
|
||||
F src/update.c 24260b4fda00c9726d27699a0561d53c0dccc397
|
||||
F src/util.c 64995b5949a5d377629ffd2598747bc771cade1e
|
||||
F src/vacuum.c 77485a64a6e4e358170f150fff681c1624a092b0
|
||||
F src/vdbe.c 763ff006f6e5a7c4dd5ba64d4967df5d49d08064
|
||||
F src/vdbe.c 802364c5b1b989ec4592aaffcbf575fa3eb0478b
|
||||
F src/vdbe.h 3957844e46fea71fd030e78f6a3bd2f7e320fb43
|
||||
F src/vdbeInt.h eab39bc209b267271bc4afbcf4991d6c229bae9a
|
||||
F src/vdbeaux.c 6f2d43643f83656b2555b7ee320397805db11d4c
|
||||
@ -88,6 +88,7 @@ F test/expr.test c4cc292d601019c2f2ce95093caaa5d10284b105
|
||||
F test/fkey1.test d65c824459916249bee501532d6154ddab0b5db7
|
||||
F test/format3.test 149cc166c97923fa60def047e90dd3fb32bba916
|
||||
F test/func.test 000515779001ac6899eec4b54e65c6e2501279d4
|
||||
F test/hook.test 1a67ce0cd64a6455d016962542f2822458dccc49
|
||||
F test/in.test 22de8a3eb27265aab723adc513bea0e76bef70c6
|
||||
F test/index.test 9295deefbdb6dedbe01be8905f0c448fe5bd4079
|
||||
F test/insert.test a17b7f7017097afb2727aa5b67ceeb7ab0a120a1
|
||||
@ -125,7 +126,7 @@ F test/sort.test ba07b107c16070208e6aab3cadea66ba079d85ba
|
||||
F test/subselect.test f0fea8cf9f386d416d64d152e3c65f9116d0f50f
|
||||
F test/table.test 371a1fc1c470982b2f68f9732f903a5d96f949c4
|
||||
F test/tableapi.test d881e787779a175238b72f55b5e50d3a85ab47a6
|
||||
F test/tclsqlite.test f141303e0f2e9a616b551813e2b21bd38c5dca50
|
||||
F test/tclsqlite.test 6921477a25aa630fd8d89b1ad231f80ef0dea88e
|
||||
F test/temptable.test c82bd6f800f10e8cf96921af6315e5f1c21e2692
|
||||
F test/tester.tcl 2671536d3650c29e7c105219f277568b0884cb58
|
||||
F test/thread1.test 0c1fcc2f9bdd887225e56f48db8ddfbb3d0794ba
|
||||
@ -179,7 +180,7 @@ F www/speed.tcl 2f6b1155b99d39adb185f900456d1d592c4832b3
|
||||
F www/sqlite.tcl 3c83b08cf9f18aa2d69453ff441a36c40e431604
|
||||
F www/tclsqlite.tcl b9271d44dcf147a93c98f8ecf28c927307abd6da
|
||||
F www/vdbe.tcl 9b9095d4495f37697fd1935d10e14c6015e80aa1
|
||||
P a9f25347de6d2bf843a8aebf7935e9c8a1f2319c
|
||||
R 8641e6b22bbcab376fe70750a642a5f8
|
||||
P c9ac3db8e08403398ec344757385334601a59374
|
||||
R 18a9d4e8ef4c6ab1b9d09a62e3e37863
|
||||
U drh
|
||||
Z 7e6cc2ec80fafcf5309e5e8766ecebcd
|
||||
Z 26c0ac18c73114906997f5ad3548f7ae
|
||||
|
@ -1 +1 @@
|
||||
c9ac3db8e08403398ec344757385334601a59374
|
||||
72bc84f2f18f6eeb279a4ad670310e85d154f663
|
20
src/main.c
20
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
|
||||
|
@ -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
|
||||
|
@ -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 */
|
||||
|
@ -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 */
|
||||
@ -357,6 +358,23 @@ static void DbTraceHandler(void *cd, const char *zSql){
|
||||
Tcl_ResetResult(pDb->interp);
|
||||
}
|
||||
|
||||
/*
|
||||
** 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
|
||||
|
@ -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);
|
||||
|
83
test/hook.test
Normal file
83
test/hook.test
Normal file
@ -0,0 +1,83 @@
|
||||
# 2004 Jan 14
|
||||
#
|
||||
# The author disclaims copyright to this source code. In place of
|
||||
# a legal notice, here is a blessing:
|
||||
#
|
||||
# May you do good and not evil.
|
||||
# May you find forgiveness for yourself and forgive others.
|
||||
# May you share freely, never taking more than you give.
|
||||
#
|
||||
#***********************************************************************
|
||||
# This file implements regression tests for TCL interface to the
|
||||
# SQLite library.
|
||||
#
|
||||
# The focus of the tests in this file is the following interface:
|
||||
#
|
||||
# sqlite_commit_hook
|
||||
#
|
||||
# $Id: hook.test,v 1.3 2004/01/15 02:44:03 drh Exp $
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
|
||||
do_test hook-1.2 {
|
||||
db commit_hook
|
||||
} {}
|
||||
|
||||
|
||||
do_test hook-3.1 {
|
||||
set commit_cnt 0
|
||||
proc commit_hook {} {
|
||||
incr ::commit_cnt
|
||||
return 0
|
||||
}
|
||||
db commit_hook ::commit_hook
|
||||
db commit_hook
|
||||
} {::commit_hook}
|
||||
do_test hook-3.2 {
|
||||
set commit_cnt
|
||||
} {0}
|
||||
do_test hook-3.3 {
|
||||
execsql {
|
||||
CREATE TABLE t2(a,b);
|
||||
}
|
||||
set commit_cnt
|
||||
} {1}
|
||||
do_test hook-3.4 {
|
||||
execsql {
|
||||
INSERT INTO t2 VALUES(1,2);
|
||||
INSERT INTO t2 SELECT a+1, b+1 FROM t2;
|
||||
INSERT INTO t2 SELECT a+2, b+2 FROM t2;
|
||||
}
|
||||
set commit_cnt
|
||||
} {4}
|
||||
do_test hook-3.5 {
|
||||
set commit_cnt {}
|
||||
proc commit_hook {} {
|
||||
set ::commit_cnt [execsql {SELECT * FROM t2}]
|
||||
return 0
|
||||
}
|
||||
execsql {
|
||||
INSERT INTO t2 VALUES(5,6);
|
||||
}
|
||||
set commit_cnt
|
||||
} {1 2 2 3 3 4 4 5 5 6}
|
||||
do_test hook-3.6 {
|
||||
set commit_cnt {}
|
||||
proc commit_hook {} {
|
||||
set ::commit_cnt [execsql {SELECT * FROM t2}]
|
||||
return 1
|
||||
}
|
||||
catchsql {
|
||||
INSERT INTO t2 VALUES(6,7);
|
||||
}
|
||||
} {1 {constraint failed}}
|
||||
do_test hook-3.7 {
|
||||
set commit_cnt
|
||||
} {1 2 2 3 3 4 4 5 5 6 6 7}
|
||||
do_test hook-3.8 {
|
||||
execsql {SELECT * FROM t2}
|
||||
} {1 2 2 3 3 4 4 5 5 6}
|
||||
|
||||
|
||||
finish_test
|
@ -15,7 +15,7 @@
|
||||
# interface is pretty well tested. This file contains some addition
|
||||
# tests for fringe issues that the main test suite does not cover.
|
||||
#
|
||||
# $Id: tclsqlite.test,v 1.16 2003/10/23 15:27:12 peter Exp $
|
||||
# $Id: tclsqlite.test,v 1.17 2004/01/15 02:44:04 drh Exp $
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
@ -29,7 +29,7 @@ do_test tcl-1.1 {
|
||||
do_test tcl-1.2 {
|
||||
set v [catch {db bogus} msg]
|
||||
lappend v $msg
|
||||
} {1 {bad option "bogus": must be authorizer, busy, changes, close, complete, errorcode, eval, function, last_insert_rowid, onecolumn, timeout, trace, or progress}}
|
||||
} {1 {bad option "bogus": must be authorizer, busy, changes, close, commit_hook, complete, errorcode, eval, function, last_insert_rowid, onecolumn, progress, timeout, or trace}}
|
||||
do_test tcl-1.3 {
|
||||
execsql {CREATE TABLE t1(a int, b int)}
|
||||
execsql {INSERT INTO t1 VALUES(10,20)}
|
||||
|
Loading…
x
Reference in New Issue
Block a user