1
0
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:
dan
2013-08-23 17:43:32 +00:00
parent 32683532f0
commit 7531a5a378
6 changed files with 185 additions and 23 deletions

69
ext/session/sessionA.test Normal file
View 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

View File

@ -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.

View File

@ -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
**

View File

@ -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]);

View File

@ -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

View File

@ -1 +1 @@
831492dca8bcfb1a1f83a8bb15de9cc94f29f07e
b7e4dd889d37c8f57c2d3c7900e802f644aac3ea