mirror of
https://github.com/sqlite/sqlite.git
synced 2025-07-30 19:03:16 +03:00
Add the sqlite3session_table_filter API to the sessions extension.
FossilOrigin-Name: b7e4dd889d37c8f57c2d3c7900e802f644aac3ea
This commit is contained in:
69
ext/session/sessionA.test
Normal file
69
ext/session/sessionA.test
Normal file
@ -0,0 +1,69 @@
|
||||
# 2013 July 04
|
||||
#
|
||||
# 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 tests that the sessions module handles foreign key constraint
|
||||
# violations when applying changesets as required.
|
||||
#
|
||||
|
||||
if {![info exists testdir]} {
|
||||
set testdir [file join [file dirname [info script]] .. .. test]
|
||||
}
|
||||
source [file join [file dirname [info script]] session_common.tcl]
|
||||
source $testdir/tester.tcl
|
||||
ifcapable !session {finish_test; return}
|
||||
set testprefix sessionA
|
||||
|
||||
|
||||
forcedelete test.db2
|
||||
sqlite3 db2 test.db2
|
||||
foreach {tn db} {1 db 2 db2} {
|
||||
do_test 1.$tn.1 {
|
||||
execsql {
|
||||
CREATE TABLE t1(a PRIMARY KEY, b);
|
||||
CREATE TABLE t2(a PRIMARY KEY, b);
|
||||
CREATE TABLE t3(a PRIMARY KEY, b);
|
||||
} $db
|
||||
} {}
|
||||
}
|
||||
|
||||
proc tbl_filter {zTbl} {
|
||||
return $::table_filter($zTbl)
|
||||
}
|
||||
|
||||
do_test 2.1 {
|
||||
set ::table_filter(t1) 1
|
||||
set ::table_filter(t2) 0
|
||||
set ::table_filter(t3) 1
|
||||
|
||||
sqlite3session S db main
|
||||
S table_filter tbl_filter
|
||||
|
||||
execsql {
|
||||
INSERT INTO t1 VALUES('a', 'b');
|
||||
INSERT INTO t2 VALUES('c', 'd');
|
||||
INSERT INTO t3 VALUES('e', 'f');
|
||||
}
|
||||
|
||||
set changeset [S changeset]
|
||||
S delete
|
||||
sqlite3changeset_apply db2 $changeset xConflict
|
||||
|
||||
execsql {
|
||||
SELECT * FROM t1;
|
||||
SELECT * FROM t2;
|
||||
SELECT * FROM t3;
|
||||
} db2
|
||||
} {a b e f}
|
||||
|
||||
|
||||
finish_test
|
||||
|
||||
|
@ -23,6 +23,8 @@ struct sqlite3_session {
|
||||
int bIndirect; /* True if all changes are indirect */
|
||||
int bAutoAttach; /* True to auto-attach tables */
|
||||
int rc; /* Non-zero if an error has occurred */
|
||||
void *pFilterCtx; /* First argument to pass to xTableFilter */
|
||||
int (*xTableFilter)(void *pCtx, const char *zTab);
|
||||
sqlite3_session *pNext; /* Next session object on same db. */
|
||||
SessionTable *pTable; /* List of attached tables */
|
||||
};
|
||||
@ -1066,6 +1068,16 @@ static void xPreUpdate(
|
||||
if( !pTab ){
|
||||
/* This branch is taken if table zName has not yet been attached to
|
||||
** this session and the auto-attach flag is set. */
|
||||
|
||||
/* If there is a table-filter configured, invoke it. If it returns 0,
|
||||
** this change will not be recorded. Break out of the loop early in
|
||||
** this case. */
|
||||
if( pSession->xTableFilter
|
||||
&& pSession->xTableFilter(pSession->pFilterCtx, zName)==0
|
||||
){
|
||||
break;
|
||||
}
|
||||
|
||||
pSession->rc = sqlite3session_attach(pSession,zName);
|
||||
if( pSession->rc ) break;
|
||||
pTab = pSession->pTable;
|
||||
@ -1170,6 +1182,19 @@ void sqlite3session_delete(sqlite3_session *pSession){
|
||||
sqlite3_free(pSession);
|
||||
}
|
||||
|
||||
/*
|
||||
** Set a table filter on a Session Object.
|
||||
*/
|
||||
void sqlite3session_table_filter(
|
||||
sqlite3_session *pSession,
|
||||
int(*xFilter)(void*, const char*),
|
||||
void *pCtx /* First argument passed to xFilter */
|
||||
){
|
||||
pSession->bAutoAttach = 1;
|
||||
pSession->pFilterCtx = pCtx;
|
||||
pSession->xTableFilter = xFilter;
|
||||
}
|
||||
|
||||
/*
|
||||
** Attach a table to a session. All subsequent changes made to the table
|
||||
** while the session object is enabled will be recorded.
|
||||
|
@ -71,6 +71,7 @@ int sqlite3session_create(
|
||||
*/
|
||||
void sqlite3session_delete(sqlite3_session *pSession);
|
||||
|
||||
|
||||
/*
|
||||
** CAPI3REF: Enable Or Disable A Session Object
|
||||
**
|
||||
@ -152,6 +153,24 @@ int sqlite3session_attach(
|
||||
const char *zTab /* Table name */
|
||||
);
|
||||
|
||||
/*
|
||||
** CAPI3REF: Set a table filter on a Session Object.
|
||||
**
|
||||
** The second argument (xFilter) is the "filter callback". For changes to rows
|
||||
** in tables that are not attached to the Session oject, the filter is called
|
||||
** to determine whether changes to the table's rows should be tracked or not.
|
||||
** If xFilter returns 0, changes is not tracked. Note that once a table is
|
||||
** attached, xFilter will not be called again.
|
||||
*/
|
||||
void sqlite3session_table_filter(
|
||||
sqlite3_session *pSession, /* Session object */
|
||||
int(*xFilter)(
|
||||
void *pCtx, /* Copy of third arg to _filter_table() */
|
||||
const char *zTab /* Table name */
|
||||
),
|
||||
void *pCtx /* First argument passed to xFilter */
|
||||
);
|
||||
|
||||
/*
|
||||
** CAPI3REF: Generate A Changeset From A Session Object
|
||||
**
|
||||
|
@ -7,18 +7,50 @@
|
||||
#include <string.h>
|
||||
#include <tcl.h>
|
||||
|
||||
typedef struct TestSession TestSession;
|
||||
struct TestSession {
|
||||
sqlite3_session *pSession;
|
||||
Tcl_Interp *interp;
|
||||
Tcl_Obj *pFilterScript;
|
||||
};
|
||||
|
||||
static int test_session_error(Tcl_Interp *interp, int rc){
|
||||
extern const char *sqlite3ErrName(int);
|
||||
Tcl_SetObjResult(interp, Tcl_NewStringObj(sqlite3ErrName(rc), -1));
|
||||
return TCL_ERROR;
|
||||
}
|
||||
|
||||
static int test_table_filter(void *pCtx, const char *zTbl){
|
||||
TestSession *p = (TestSession*)pCtx;
|
||||
Tcl_Obj *pEval;
|
||||
int rc;
|
||||
int bRes = 0;
|
||||
|
||||
pEval = Tcl_DuplicateObj(p->pFilterScript);
|
||||
Tcl_IncrRefCount(pEval);
|
||||
rc = Tcl_ListObjAppendElement(p->interp, pEval, Tcl_NewStringObj(zTbl, -1));
|
||||
if( rc==TCL_OK ){
|
||||
rc = Tcl_EvalObjEx(p->interp, pEval, TCL_EVAL_GLOBAL);
|
||||
}
|
||||
if( rc==TCL_OK ){
|
||||
rc = Tcl_GetBooleanFromObj(p->interp, Tcl_GetObjResult(p->interp), &bRes);
|
||||
}
|
||||
if( rc!=TCL_OK ){
|
||||
/* printf("error: %s\n", Tcl_GetStringResult(p->interp)); */
|
||||
Tcl_BackgroundError(p->interp);
|
||||
}
|
||||
Tcl_DecrRefCount(pEval);
|
||||
|
||||
return bRes;
|
||||
}
|
||||
|
||||
/*
|
||||
** Tclcmd: $session attach TABLE
|
||||
** $session changeset
|
||||
** $session delete
|
||||
** $session enable BOOL
|
||||
** $session indirect INTEGER
|
||||
** $session table_filter SCRIPT
|
||||
*/
|
||||
static int test_session_cmd(
|
||||
void *clientData,
|
||||
@ -26,19 +58,21 @@ static int test_session_cmd(
|
||||
int objc,
|
||||
Tcl_Obj *CONST objv[]
|
||||
){
|
||||
sqlite3_session *pSession = (sqlite3_session *)clientData;
|
||||
TestSession *p = (TestSession*)clientData;
|
||||
sqlite3_session *pSession = p->pSession;
|
||||
struct SessionSubcmd {
|
||||
const char *zSub;
|
||||
int nArg;
|
||||
const char *zMsg;
|
||||
int iSub;
|
||||
} aSub[] = {
|
||||
{ "attach", 1, "TABLE", }, /* 0 */
|
||||
{ "changeset", 0, "", }, /* 1 */
|
||||
{ "delete", 0, "", }, /* 2 */
|
||||
{ "enable", 1, "BOOL", }, /* 3 */
|
||||
{ "indirect", 1, "BOOL", }, /* 4 */
|
||||
{ "isempty", 0, "", }, /* 5 */
|
||||
{ "attach", 1, "TABLE", }, /* 0 */
|
||||
{ "changeset", 0, "", }, /* 1 */
|
||||
{ "delete", 0, "", }, /* 2 */
|
||||
{ "enable", 1, "BOOL", }, /* 3 */
|
||||
{ "indirect", 1, "BOOL", }, /* 4 */
|
||||
{ "isempty", 0, "", }, /* 5 */
|
||||
{ "table_filter", 1, "SCRIPT", }, /* 6 */
|
||||
{ 0 }
|
||||
};
|
||||
int iSub;
|
||||
@ -65,8 +99,8 @@ static int test_session_cmd(
|
||||
if( rc!=SQLITE_OK ){
|
||||
return test_session_error(interp, rc);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 1: { /* changeset */
|
||||
int nChange;
|
||||
@ -107,14 +141,25 @@ static int test_session_cmd(
|
||||
Tcl_SetObjResult(interp, Tcl_NewBooleanObj(val));
|
||||
break;
|
||||
}
|
||||
|
||||
case 6: { /* table_filter */
|
||||
if( p->pFilterScript ) Tcl_DecrRefCount(p->pFilterScript);
|
||||
p->interp = interp;
|
||||
p->pFilterScript = Tcl_DuplicateObj(objv[2]);
|
||||
Tcl_IncrRefCount(p->pFilterScript);
|
||||
sqlite3session_table_filter(pSession, test_table_filter, clientData);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
static void test_session_del(void *clientData){
|
||||
sqlite3_session *pSession = (sqlite3_session *)clientData;
|
||||
sqlite3session_delete(pSession);
|
||||
TestSession *p = (TestSession*)clientData;
|
||||
if( p->pFilterScript ) Tcl_DecrRefCount(p->pFilterScript);
|
||||
sqlite3session_delete(p->pSession);
|
||||
ckfree(p);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -129,7 +174,7 @@ static int test_sqlite3session(
|
||||
sqlite3 *db;
|
||||
Tcl_CmdInfo info;
|
||||
int rc; /* sqlite3session_create() return code */
|
||||
sqlite3_session *pSession; /* New session object */
|
||||
TestSession *p; /* New wrapper object */
|
||||
|
||||
if( objc!=4 ){
|
||||
Tcl_WrongNumArgs(interp, 1, objv, "CMD DB-HANDLE DB-NAME");
|
||||
@ -142,13 +187,16 @@ static int test_sqlite3session(
|
||||
}
|
||||
db = *(sqlite3 **)info.objClientData;
|
||||
|
||||
rc = sqlite3session_create(db, Tcl_GetString(objv[3]), &pSession);
|
||||
p = (TestSession*)ckalloc(sizeof(TestSession));
|
||||
memset(p, 0, sizeof(TestSession));
|
||||
rc = sqlite3session_create(db, Tcl_GetString(objv[3]), &p->pSession);
|
||||
if( rc!=SQLITE_OK ){
|
||||
ckfree(p);
|
||||
return test_session_error(interp, rc);
|
||||
}
|
||||
|
||||
Tcl_CreateObjCommand(
|
||||
interp, Tcl_GetString(objv[1]), test_session_cmd, (ClientData)pSession,
|
||||
interp, Tcl_GetString(objv[1]), test_session_cmd, (ClientData)p,
|
||||
test_session_del
|
||||
);
|
||||
Tcl_SetObjResult(interp, objv[1]);
|
||||
|
19
manifest
19
manifest
@ -1,5 +1,5 @@
|
||||
C Merge\sin\sminor\sbug\sfixes\sand\sperformance\stweaks\sfrom\strunk\sleading\sup\sto\nthe\sversion\s3.8.0\srelease.
|
||||
D 2013-08-22T15:07:08.266
|
||||
C Add\sthe\ssqlite3session_table_filter\sAPI\sto\sthe\ssessions\sextension.
|
||||
D 2013-08-23T17:43:32.715
|
||||
F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
|
||||
F Makefile.in aff38bc64c582dd147f18739532198372587b0f0
|
||||
F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
|
||||
@ -144,11 +144,12 @@ F ext/session/session5.test 8fdfaf9dba28a2f1c6b89b06168bdab1fef2d478
|
||||
F ext/session/session6.test 443789bc2fca12e4f7075cf692c60b8a2bea1a26
|
||||
F ext/session/session8.test 7d35947ad329b8966f095d34f9617a9eff52dc65
|
||||
F ext/session/session9.test 43acfdc57647c2ce4b36dbd0769112520ea6af14
|
||||
F ext/session/sessionA.test eb05c13e4ef1ca8046a3a6dbf2d5f6f5b04a11d4
|
||||
F ext/session/session_common.tcl 1539d8973b2aea0025c133eb0cc4c89fcef541a5
|
||||
F ext/session/sessionfault.test 496291b287ba3c0b14ca2e074425e29cc92a64a6
|
||||
F ext/session/sqlite3session.c e0345e8425a36fb8ac107175ebae46b4af8873e4
|
||||
F ext/session/sqlite3session.h c7db3d8515eba7f41eeb8698a25e58d24cd384bf
|
||||
F ext/session/test_session.c 12053e9190653164fa624427cf90d1f46ca7f179
|
||||
F ext/session/sqlite3session.c 63eea3741e8ac1574d4c183fd92a6a50b1415357
|
||||
F ext/session/sqlite3session.h 6c35057241567ed6319f750ee504a81c459225e1
|
||||
F ext/session/test_session.c d38968307c05229cc8cd603722cf305d6f768832
|
||||
F install-sh 9d4de14ab9fb0facae2f48780b874848cbf2f895 x
|
||||
F ltmain.sh 3ff0879076df340d2e23ae905484d8c15d5fdea8
|
||||
F magic.txt f2b23a6bde8f1c6e86b957e4d94eab0add520b0d
|
||||
@ -1119,7 +1120,7 @@ F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4
|
||||
F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381
|
||||
F tool/wherecosttest.c f407dc4c79786982a475261866a161cd007947ae
|
||||
F tool/win/sqlite.vsix 97894c2790eda7b5bce3cc79cb2a8ec2fde9b3ac
|
||||
P 3e4033285deb417bd72c008917729dbf3bf4e90d 0775501acf152dcbf4dd039f4511f3d8c4330d85
|
||||
R f6e422c39c44105817eb40d9d54618de
|
||||
U drh
|
||||
Z f9597afebde4efa08f5ab31e24bede7f
|
||||
P 831492dca8bcfb1a1f83a8bb15de9cc94f29f07e
|
||||
R cbce615b433685cc6c1cb9210155f0f8
|
||||
U dan
|
||||
Z 2d1cb3afe326cb66267c2981ea353dde
|
||||
|
@ -1 +1 @@
|
||||
831492dca8bcfb1a1f83a8bb15de9cc94f29f07e
|
||||
b7e4dd889d37c8f57c2d3c7900e802f644aac3ea
|
Reference in New Issue
Block a user