diff options
author | dan <dan@noemail.net> | 2011-03-25 10:52:01 +0000 |
---|---|---|
committer | dan <dan@noemail.net> | 2011-03-25 10:52:01 +0000 |
commit | f51e5f6c9950c9ed0efcbca08608f462bb4db0ed (patch) | |
tree | c85585cb6d5c3eeba9874314fcc1df7933c7ed4e | |
parent | a9605b912552c6d6b33c787917d79187fbf4c3ce (diff) | |
download | sqlite-f51e5f6c9950c9ed0efcbca08608f462bb4db0ed.tar.gz sqlite-f51e5f6c9950c9ed0efcbca08608f462bb4db0ed.zip |
Improve coverage of session module code.
FossilOrigin-Name: 666123c8d07be87d477e67b1cebef2b0fba5b4bc
-rw-r--r-- | ext/session/session2.test | 145 | ||||
-rw-r--r-- | ext/session/session3.test | 6 | ||||
-rw-r--r-- | ext/session/session4.test | 62 | ||||
-rw-r--r-- | ext/session/sqlite3session.c | 3 | ||||
-rw-r--r-- | ext/session/sqlite3session.h | 3 | ||||
-rw-r--r-- | ext/session/test_session.c | 57 | ||||
-rw-r--r-- | manifest | 21 | ||||
-rw-r--r-- | manifest.uuid | 2 |
8 files changed, 274 insertions, 25 deletions
diff --git a/ext/session/session2.test b/ext/session/session2.test index a4776d80e..6662173d4 100644 --- a/ext/session/session2.test +++ b/ext/session/session2.test @@ -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 diff --git a/ext/session/session3.test b/ext/session/session3.test index d0d2c31fa..a0946f309 100644 --- a/ext/session/session3.test +++ b/ext/session/session3.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] diff --git a/ext/session/session4.test b/ext/session/session4.test new file mode 100644 index 000000000..c69fa85fc --- /dev/null +++ b/ext/session/session4.test @@ -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 diff --git a/ext/session/sqlite3session.c b/ext/session/sqlite3session.c index ffc2e13f5..36d83e6b8 100644 --- a/ext/session/sqlite3session.c +++ b/ext/session/sqlite3session.c @@ -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: diff --git a/ext/session/sqlite3session.h b/ext/session/sqlite3session.h index 5d19379ec..bcb901667 100644 --- a/ext/session/sqlite3session.h +++ b/ext/session/sqlite3session.h @@ -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 */ diff --git a/ext/session/test_session.c b/ext/session/test_session.c index e3d6d60c2..4befd0fe6 100644 --- a/ext/session/test_session.c +++ b/ext/session/test_session.c @@ -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); } } @@ -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 diff --git a/manifest.uuid b/manifest.uuid index 5f9877e0e..c8072ced9 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -76d2d2ad3b2a5171393b7894f35f463ff284e53b
\ No newline at end of file +666123c8d07be87d477e67b1cebef2b0fba5b4bc
\ No newline at end of file |