sl@0: # 2007 September 7 sl@0: # sl@0: # The author disclaims copyright to this source code. In place of sl@0: # a legal notice, here is a blessing: sl@0: # sl@0: # May you do good and not evil. sl@0: # May you find forgiveness for yourself and forgive others. sl@0: # May you share freely, never taking more than you give. sl@0: # sl@0: #*********************************************************************** sl@0: # sl@0: # $Id: thread001.test,v 1.5 2008/07/12 14:52:20 drh Exp $ sl@0: sl@0: set testdir [file dirname $argv0] sl@0: sl@0: source $testdir/tester.tcl sl@0: source $testdir/thread_common.tcl sl@0: if {[info commands sqlthread] eq ""} { sl@0: return sl@0: } sl@0: sl@0: set ::NTHREAD 10 sl@0: sl@0: # Run this test three times: sl@0: # sl@0: # 1) All threads use the same database handle. sl@0: # 2) All threads use their own database handles. sl@0: # 3) All threads use their own database handles, shared-cache is enabled. sl@0: # sl@0: foreach {tn same_db shared_cache} [list \ sl@0: 1 1 0 \ sl@0: 2 0 0 \ sl@0: 3 0 1 \ sl@0: ] { sl@0: # Empty the database. sl@0: # sl@0: catchsql { DROP TABLE ab; } sl@0: sl@0: do_test thread001.$tn.0 { sl@0: db close sl@0: sqlite3_enable_shared_cache $shared_cache sl@0: sqlite3_enable_shared_cache $shared_cache sl@0: } $shared_cache sl@0: sqlite3 db test.db sl@0: sl@0: set dbconfig "" sl@0: if {$same_db} { sl@0: set dbconfig [list set ::DB [sqlite3_connection_pointer db]] sl@0: } sl@0: sl@0: # Set up a database and a schema. The database contains a single sl@0: # table with two columns. The first column ("a") is an INTEGER PRIMARY sl@0: # KEY. The second contains the md5sum of all rows in the table with sl@0: # a smaller value stored in column "a". sl@0: # sl@0: do_test thread001.$tn.1 { sl@0: execsql { sl@0: CREATE TABLE ab(a INTEGER PRIMARY KEY, b); sl@0: CREATE INDEX ab_i ON ab(b); sl@0: INSERT INTO ab SELECT NULL, md5sum(a, b) FROM ab; sl@0: SELECT count(*) FROM ab; sl@0: } sl@0: } {1} sl@0: do_test thread001.$tn.2 { sl@0: execsql { sl@0: SELECT sl@0: (SELECT md5sum(a, b) FROM ab WHERE a < (SELECT max(a) FROM ab)) == sl@0: (SELECT b FROM ab WHERE a = (SELECT max(a) FROM ab)) sl@0: } sl@0: } {1} sl@0: do_test thread001.$tn.3 { sl@0: execsql { PRAGMA integrity_check } sl@0: } {ok} sl@0: sl@0: set thread_program { sl@0: set needToClose 0 sl@0: if {![info exists ::DB]} { sl@0: set ::DB [sqlthread open test.db] sl@0: set needToClose 1 sl@0: } sl@0: sl@0: for {set i 0} {$i < 100} {incr i} { sl@0: # Test that the invariant is true. sl@0: do_test t1 { sl@0: execsql { sl@0: SELECT sl@0: (SELECT md5sum(a, b) FROM ab WHERE a < (SELECT max(a) FROM ab)) == sl@0: (SELECT b FROM ab WHERE a = (SELECT max(a) FROM ab)) sl@0: } sl@0: } {1} sl@0: sl@0: # Add another row to the database. sl@0: execsql { INSERT INTO ab SELECT NULL, md5sum(a, b) FROM ab } sl@0: } sl@0: sl@0: if {$needToClose} { sl@0: sqlite3_close $::DB sl@0: } sl@0: sl@0: list OK sl@0: } sl@0: sl@0: # Kick off $::NTHREAD threads: sl@0: # sl@0: array unset finished sl@0: for {set i 0} {$i < $::NTHREAD} {incr i} { sl@0: thread_spawn finished($i) $dbconfig $thread_procs $thread_program sl@0: } sl@0: sl@0: # Wait for all threads to finish, then check they all returned "OK". sl@0: # sl@0: for {set i 0} {$i < $::NTHREAD} {incr i} { sl@0: if {![info exists finished($i)]} { sl@0: vwait finished($i) sl@0: } sl@0: do_test thread001.$tn.4.$i { sl@0: set ::finished($i) sl@0: } OK sl@0: } sl@0: sl@0: # Check the database still looks Ok. sl@0: # sl@0: do_test thread001.$tn.5 { sl@0: execsql { SELECT count(*) FROM ab; } sl@0: } [expr {1 + $::NTHREAD*100}] sl@0: do_test thread001.$tn.6 { sl@0: execsql { sl@0: SELECT sl@0: (SELECT md5sum(a, b) FROM ab WHERE a < (SELECT max(a) FROM ab)) == sl@0: (SELECT b FROM ab WHERE a = (SELECT max(a) FROM ab)) sl@0: } sl@0: } {1} sl@0: do_test thread001.$tn.7 { sl@0: execsql { PRAGMA integrity_check } sl@0: } {ok} sl@0: } sl@0: sl@0: finish_test