aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authordan <dan@noemail.net>2011-03-25 10:52:01 +0000
committerdan <dan@noemail.net>2011-03-25 10:52:01 +0000
commitf51e5f6c9950c9ed0efcbca08608f462bb4db0ed (patch)
treec85585cb6d5c3eeba9874314fcc1df7933c7ed4e
parenta9605b912552c6d6b33c787917d79187fbf4c3ce (diff)
downloadsqlite-f51e5f6c9950c9ed0efcbca08608f462bb4db0ed.tar.gz
sqlite-f51e5f6c9950c9ed0efcbca08608f462bb4db0ed.zip
Improve coverage of session module code.
FossilOrigin-Name: 666123c8d07be87d477e67b1cebef2b0fba5b4bc
-rw-r--r--ext/session/session2.test145
-rw-r--r--ext/session/session3.test6
-rw-r--r--ext/session/session4.test62
-rw-r--r--ext/session/sqlite3session.c3
-rw-r--r--ext/session/sqlite3session.h3
-rw-r--r--ext/session/test_session.c57
-rw-r--r--manifest21
-rw-r--r--manifest.uuid2
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);
}
}
diff --git a/manifest b/manifest
index 1f7e7a7bd..a8b17c0fc 100644
--- a/manifest
+++ b/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
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