mirror of
https://github.com/sqlite/sqlite.git
synced 2025-07-24 22:22:08 +03:00
Improve coverage of session module code.
FossilOrigin-Name: 666123c8d07be87d477e67b1cebef2b0fba5b4bc
This commit is contained in:
@ -377,4 +377,149 @@ do_iterator_test 6.1.7 * {
|
||||
{UPDATE t2 0 X. {i 4 t y} {{} {} t new}}
|
||||
}
|
||||
|
||||
sqlite3session S db main
|
||||
do_execsql_test 6.2.1 {
|
||||
SELECT indirect(0);
|
||||
SELECT indirect(-1);
|
||||
SELECT indirect(45);
|
||||
SELECT indirect(-100);
|
||||
} {0 0 1 1}
|
||||
S delete
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Test that if a conflict-handler that has been passed either NOTFOUND or
|
||||
# CONSTRAINT returns REPLACE - the sqlite3changeset_apply() call returns
|
||||
# MISUSE and rolls back any changes made so far.
|
||||
#
|
||||
# 7.1.*: NOTFOUND conflict-callback.
|
||||
# 7.2.*: CONSTRAINT conflict-callback.
|
||||
#
|
||||
proc xConflict {args} {return REPLACE}
|
||||
test_reset
|
||||
|
||||
do_execsql_test 7.1.1 {
|
||||
CREATE TABLE t1(a PRIMARY KEY, b);
|
||||
INSERT INTO t1 VALUES(1, 'one');
|
||||
INSERT INTO t1 VALUES(2, 'two');
|
||||
}
|
||||
do_test 7.1.2 {
|
||||
execsql {
|
||||
CREATE TABLE t1(a PRIMARY KEY, b NOT NULL);
|
||||
INSERT INTO t1 VALUES(1, 'one');
|
||||
} db2
|
||||
} {}
|
||||
do_test 7.1.3 {
|
||||
set changeset [changeset_from_sql {
|
||||
UPDATE t1 SET b = 'five' WHERE a = 1;
|
||||
UPDATE t1 SET b = 'six' WHERE a = 2;
|
||||
}]
|
||||
set x [list]
|
||||
sqlite3session_foreach c $changeset { lappend x $c }
|
||||
set x
|
||||
} [list \
|
||||
{UPDATE t1 0 X. {i 1 t one} {{} {} t five}} \
|
||||
{UPDATE t1 0 X. {i 2 t two} {{} {} t six}} \
|
||||
]
|
||||
do_test 7.1.4 {
|
||||
list [catch {sqlite3changeset_apply db2 $changeset xConflict} msg] $msg
|
||||
} {1 SQLITE_MISUSE}
|
||||
do_test 7.1.5 { execsql { SELECT * FROM t1 } db2 } {1 one}
|
||||
|
||||
do_test 7.2.1 {
|
||||
set changeset [changeset_from_sql { UPDATE t1 SET b = NULL WHERE a = 1 }]
|
||||
|
||||
set x [list]
|
||||
sqlite3session_foreach c $changeset { lappend x $c }
|
||||
set x
|
||||
} [list \
|
||||
{UPDATE t1 0 X. {i 1 t five} {{} {} n {}}} \
|
||||
]
|
||||
do_test 7.2.2 {
|
||||
list [catch {sqlite3changeset_apply db2 $changeset xConflict} msg] $msg
|
||||
} {1 SQLITE_MISUSE}
|
||||
do_test 7.2.3 { execsql { SELECT * FROM t1 } db2 } {1 one}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Test that if a conflict-handler returns ABORT, application of the
|
||||
# changeset is rolled back and the sqlite3changeset_apply() method returns
|
||||
# SQLITE_ABORT.
|
||||
#
|
||||
# Also test that the same thing happens if a conflict handler returns an
|
||||
# unrecognized integer value. Except, in this case SQLITE_MISUSE is returned
|
||||
# instead of SQLITE_ABORT.
|
||||
#
|
||||
foreach {tn conflict_return apply_return} {
|
||||
1 ABORT SQLITE_ABORT
|
||||
2 567 SQLITE_MISUSE
|
||||
} {
|
||||
test_reset
|
||||
proc xConflict {args} [list return $conflict_return]
|
||||
|
||||
do_test 8.$tn.0 {
|
||||
do_common_sql {
|
||||
CREATE TABLE t1(x, y, PRIMARY KEY(x, y));
|
||||
INSERT INTO t1 VALUES('x', 'y');
|
||||
}
|
||||
execsql { INSERT INTO t1 VALUES('w', 'w') }
|
||||
|
||||
set changeset [changeset_from_sql { DELETE FROM t1 WHERE 1 }]
|
||||
|
||||
set x [list]
|
||||
sqlite3session_foreach c $changeset { lappend x $c }
|
||||
set x
|
||||
} [list \
|
||||
{DELETE t1 0 XX {t w t w} {}} \
|
||||
{DELETE t1 0 XX {t x t y} {}} \
|
||||
]
|
||||
|
||||
do_test 8.$tn.1 {
|
||||
list [catch {sqlite3changeset_apply db2 $changeset xConflict} msg] $msg
|
||||
} [list 1 $apply_return]
|
||||
|
||||
do_test 8.$tn.2 {
|
||||
execsql {SELECT * FROM t1} db2
|
||||
} {x y}
|
||||
}
|
||||
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Try to cause an infinite loop as follows:
|
||||
#
|
||||
# 1. Have a changeset insert a row that causes a CONFLICT callback,
|
||||
# 2. Have the conflict handler return REPLACE,
|
||||
# 3. After the session module deletes the conflicting row, have a trigger
|
||||
# re-insert it.
|
||||
# 4. Goto step 1...
|
||||
#
|
||||
# This doesn't work, as the second invocation of the conflict handler is a
|
||||
# CONSTRAINT, not a CONFLICT. There is at most one CONFLICT callback for
|
||||
# each change in the changeset.
|
||||
#
|
||||
test_reset
|
||||
proc xConflict {type args} {
|
||||
if {$type == "CONFLICT"} { return REPLACE }
|
||||
return OMIT
|
||||
}
|
||||
do_test 9.1 {
|
||||
execsql {
|
||||
CREATE TABLE t1(a PRIMARY KEY, b);
|
||||
}
|
||||
execsql {
|
||||
CREATE TABLE t1(a PRIMARY KEY, b);
|
||||
INSERT INTO t1 VALUES('x', 2);
|
||||
CREATE TRIGGER tr1 AFTER DELETE ON t1 BEGIN
|
||||
INSERT INTO t1 VALUES(old.a, old.b);
|
||||
END;
|
||||
} db2
|
||||
} {}
|
||||
do_test 9.2 {
|
||||
set changeset [changeset_from_sql { INSERT INTO t1 VALUES('x', 1) }]
|
||||
sqlite3changeset_apply db2 $changeset xConflict
|
||||
} {}
|
||||
do_test 9.3 {
|
||||
execsql { SELECT * FROM t1 } db2
|
||||
} {x 2}
|
||||
|
||||
|
||||
|
||||
finish_test
|
||||
|
@ -8,8 +8,10 @@
|
||||
# May you share freely, never taking more than you give.
|
||||
#
|
||||
#***********************************************************************
|
||||
# This file implements regression tests for the session module.
|
||||
#
|
||||
# This file implements regression tests for the session module. More
|
||||
# specifically, it focuses on testing the session modules response to
|
||||
# database schema modifications and mismatches.
|
||||
#
|
||||
|
||||
if {![info exists testdir]} {
|
||||
set testdir [file join [file dirname [info script]] .. .. test]
|
||||
|
62
ext/session/session4.test
Normal file
62
ext/session/session4.test
Normal file
@ -0,0 +1,62 @@
|
||||
# 2011 March 25
|
||||
#
|
||||
# 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 the session module.
|
||||
#
|
||||
|
||||
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
|
||||
|
||||
set testprefix session4
|
||||
|
||||
do_test 1.0 {
|
||||
execsql {
|
||||
CREATE TABLE x(a, b, c, d, e, PRIMARY KEY(c, e));
|
||||
INSERT INTO x VALUES(65.21, X'28B0', 16.35, NULL, 'doers');
|
||||
INSERT INTO x VALUES(NULL, 78.49, 2, X'60', -66);
|
||||
INSERT INTO x VALUES('cathedral', NULL, 35, NULL, X'B220937E80A2D8');
|
||||
INSERT INTO x VALUES(NULL, 'masking', -91.37, NULL, X'596D');
|
||||
INSERT INTO x VALUES(19, 'domains', 'espouse', -94, 'throw');
|
||||
}
|
||||
|
||||
sqlite3session S db main
|
||||
set changeset [changeset_from_sql {
|
||||
DELETE FROM x WHERE e = -66;
|
||||
UPDATE x SET a = 'parameterizable', b = 31.8 WHERE c = 35;
|
||||
INSERT INTO x VALUES(-75.61, -17, 16.85, NULL, X'D73DB02678');
|
||||
}]
|
||||
set {} {}
|
||||
} {}
|
||||
|
||||
|
||||
# This currently causes crashes. sqlite3changeset_invert() does not handle
|
||||
# corrupt changesets well.
|
||||
if 0 {
|
||||
do_test 1.1 {
|
||||
for {set i 0} {$i < [string length $changeset]} {incr i} {
|
||||
set before [string range $changeset 0 [expr $i-1]]
|
||||
set after [string range $changeset [expr $i+1] end]
|
||||
for {set j 10} {$j < 260} {incr j} {
|
||||
set x [binary format "a*ca*" $before $j $after]
|
||||
catch { sqlite3changeset_invert $x }
|
||||
}
|
||||
}
|
||||
} {}
|
||||
}
|
||||
|
||||
do_test 1.2 {
|
||||
set x [binary format "ca*" 0 [string range $changeset 1 end]]
|
||||
list [catch { sqlite3changeset_invert $x } msg] $msg
|
||||
} {1 SQLITE_CORRUPT}
|
||||
|
||||
finish_test
|
@ -2255,7 +2255,8 @@ static int sessionConflictHandler(
|
||||
if( rc==SQLITE_OK ){
|
||||
switch( res ){
|
||||
case SQLITE_CHANGESET_REPLACE:
|
||||
if( pbReplace ) *pbReplace = 1;
|
||||
assert( pbReplace );
|
||||
*pbReplace = 1;
|
||||
break;
|
||||
|
||||
case SQLITE_CHANGESET_OMIT:
|
||||
|
@ -513,6 +513,9 @@ int sqlite3changeset_finalize(sqlite3_changeset_iter *pIter);
|
||||
** It is the responsibility of the caller to eventually call sqlite3_free()
|
||||
** on the *ppOut pointer to free the buffer allocation following a successful
|
||||
** call to this function.
|
||||
**
|
||||
** WARNING/TODO: This function currently assumes that the input is a valid
|
||||
** changeset. If it is not, the results are undefined.
|
||||
*/
|
||||
int sqlite3changeset_invert(
|
||||
int nIn, void *pIn, /* Input changeset */
|
||||
|
@ -17,7 +17,7 @@ static int test_session_error(Tcl_Interp *interp, int rc){
|
||||
** $session changeset
|
||||
** $session delete
|
||||
** $session enable BOOL
|
||||
** $session indirect BOOL
|
||||
** $session indirect INTEGER
|
||||
*/
|
||||
static int test_session_cmd(
|
||||
void *clientData,
|
||||
@ -93,7 +93,7 @@ static int test_session_cmd(
|
||||
|
||||
case 4: { /* indirect */
|
||||
int val;
|
||||
if( Tcl_GetBooleanFromObj(interp, objv[2], &val) ) return TCL_ERROR;
|
||||
if( Tcl_GetIntFromObj(interp, objv[2], &val) ) return TCL_ERROR;
|
||||
val = sqlite3session_indirect(pSession, val);
|
||||
Tcl_SetObjResult(interp, Tcl_NewBooleanObj(val));
|
||||
break;
|
||||
@ -268,18 +268,59 @@ static int test_conflict_handler(
|
||||
}
|
||||
|
||||
/* If this is a CHANGESET_DATA or CHANGESET_CONFLICT conflict, append
|
||||
** the conflicting row. */
|
||||
** the conflicting row. */
|
||||
if( eConf==SQLITE_CHANGESET_DATA || eConf==SQLITE_CHANGESET_CONFLICT ){
|
||||
int i;
|
||||
Tcl_Obj *pConflict = Tcl_NewObj();
|
||||
for(i=0; i<nCol; i++){
|
||||
int rc;
|
||||
sqlite3_value *pVal;
|
||||
sqlite3changeset_conflict(pIter, i, &pVal);
|
||||
rc = sqlite3changeset_conflict(pIter, i, &pVal);
|
||||
assert( rc==SQLITE_OK );
|
||||
test_append_value(pConflict, pVal);
|
||||
}
|
||||
Tcl_ListObjAppendElement(0, pEval, pConflict);
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
** This block is purely for testing some error conditions.
|
||||
*/
|
||||
if( eConf==SQLITE_CHANGESET_CONSTRAINT || eConf==SQLITE_CHANGESET_NOTFOUND ){
|
||||
sqlite3_value *pVal;
|
||||
int rc = sqlite3changeset_conflict(pIter, 0, &pVal);
|
||||
assert( rc==SQLITE_MISUSE );
|
||||
}else{
|
||||
sqlite3_value *pVal;
|
||||
int rc = sqlite3changeset_conflict(pIter, -1, &pVal);
|
||||
assert( rc==SQLITE_RANGE );
|
||||
rc = sqlite3changeset_conflict(pIter, nCol, &pVal);
|
||||
assert( rc==SQLITE_RANGE );
|
||||
}
|
||||
if( op==SQLITE_DELETE ){
|
||||
sqlite3_value *pVal;
|
||||
int rc = sqlite3changeset_new(pIter, 0, &pVal);
|
||||
assert( rc==SQLITE_MISUSE );
|
||||
}else{
|
||||
sqlite3_value *pVal;
|
||||
int rc = sqlite3changeset_new(pIter, -1, &pVal);
|
||||
assert( rc==SQLITE_RANGE );
|
||||
rc = sqlite3changeset_new(pIter, nCol, &pVal);
|
||||
assert( rc==SQLITE_RANGE );
|
||||
}
|
||||
if( op==SQLITE_INSERT ){
|
||||
sqlite3_value *pVal;
|
||||
int rc = sqlite3changeset_old(pIter, 0, &pVal);
|
||||
assert( rc==SQLITE_MISUSE );
|
||||
}else{
|
||||
sqlite3_value *pVal;
|
||||
int rc = sqlite3changeset_old(pIter, -1, &pVal);
|
||||
assert( rc==SQLITE_RANGE );
|
||||
rc = sqlite3changeset_old(pIter, nCol, &pVal);
|
||||
assert( rc==SQLITE_RANGE );
|
||||
}
|
||||
/* End of testing block
|
||||
***********************************************************************/
|
||||
|
||||
if( TCL_OK!=Tcl_EvalObjEx(interp, pEval, TCL_EVAL_GLOBAL) ){
|
||||
Tcl_BackgroundError(interp);
|
||||
}else{
|
||||
@ -291,13 +332,7 @@ static int test_conflict_handler(
|
||||
}else if( test_obj_eq_string(pRes, "ABORT") ){
|
||||
ret = SQLITE_CHANGESET_ABORT;
|
||||
}else{
|
||||
Tcl_IncrRefCount(pRes);
|
||||
Tcl_ResetResult(interp);
|
||||
Tcl_AppendResult(interp, "unrecognized conflict handler return: \"",
|
||||
Tcl_GetString(pRes), "\"", 0
|
||||
);
|
||||
Tcl_DecrRefCount(pRes);
|
||||
Tcl_BackgroundError(interp);
|
||||
Tcl_GetIntFromObj(0, pRes, &ret);
|
||||
}
|
||||
}
|
||||
|
||||
|
21
manifest
21
manifest
@ -1,5 +1,5 @@
|
||||
C Fix\shandling\sof\sschema\schanges\smid-session.
|
||||
D 2011-03-24T16:53:57
|
||||
C Improve\scoverage\sof\ssession\smodule\scode.
|
||||
D 2011-03-25T10:52:02
|
||||
F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
|
||||
F Makefile.in 27701a1653595a1f2187dc61c8117e00a6c1d50f
|
||||
F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
|
||||
@ -100,13 +100,14 @@ F ext/rtree/sqlite3rtree.h 1af0899c63a688e272d69d8e746f24e76f10a3f0
|
||||
F ext/rtree/tkt3363.test 142ab96eded44a3615ec79fba98c7bde7d0f96de
|
||||
F ext/rtree/viewrtree.tcl eea6224b3553599ae665b239bd827e182b466024
|
||||
F ext/session/session1.test b2da15b9d727d7f4e5fe95599b32b92d93b5a970
|
||||
F ext/session/session2.test 8da094318ac88953478c43d0bfb0aa723ee0e379
|
||||
F ext/session/session3.test c58ebb3273a23da9b5f4eb202d522aa759530a4c
|
||||
F ext/session/session2.test f2f0bad3f27c9084f5f51444d017ede485cee009
|
||||
F ext/session/session3.test 5b2e9d0b94af5d7770f89e020d83b838584ccc64
|
||||
F ext/session/session4.test 3b39b468bf871f3b7825f64f9ce9f3849ff4b156
|
||||
F ext/session/session_common.tcl fb91560b6dbd086010df8b3a137a452f1ac21a28
|
||||
F ext/session/sessionfault.test d7e6154a30e85622d0733b1a1e3c63e9b8b7004b
|
||||
F ext/session/sqlite3session.c 33a5d4be9c22099aed8e7f6c80b63540953e84c2
|
||||
F ext/session/sqlite3session.h 900d900bb6a827f84754fc252a05638e0f413a6e
|
||||
F ext/session/test_session.c e0f500ec5e20478afc2c7998133e8acea7ec5104
|
||||
F ext/session/sqlite3session.c 8057ed55d25c4d487ec8b68a3ee1c2c25dd543da
|
||||
F ext/session/sqlite3session.h f284bac51c12de0e0096fc986e61f5ae6b9e5be5
|
||||
F ext/session/test_session.c 5f186a9f45958620ebc0609099538eb7cabdfe84
|
||||
F install-sh 9d4de14ab9fb0facae2f48780b874848cbf2f895
|
||||
F ltmain.sh 3ff0879076df340d2e23ae905484d8c15d5fdea8
|
||||
F main.mk ae0868e05c76eaa8a0ae3d6927a949b1c8e810d7
|
||||
@ -924,7 +925,7 @@ F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff
|
||||
F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224
|
||||
F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e
|
||||
F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f
|
||||
P 506a0d7a710e1ff2f367821e73f5080fcf63fbc5
|
||||
R 3234ab73592ecae31c60c0a6f501bbfd
|
||||
P 76d2d2ad3b2a5171393b7894f35f463ff284e53b
|
||||
R b7843eac9e1de41d0b79cfdd795816c8
|
||||
U dan
|
||||
Z 29af2cd6e2d7044fdb214ebc342ad1ba
|
||||
Z 4c90a35f73d811b840852d363dcb9fdc
|
||||
|
@ -1 +1 @@
|
||||
76d2d2ad3b2a5171393b7894f35f463ff284e53b
|
||||
666123c8d07be87d477e67b1cebef2b0fba5b4bc
|
Reference in New Issue
Block a user