1# 2007 September 7 2# 3# The author disclaims copyright to this source code. In place of 4# a legal notice, here is a blessing: 5# 6# May you do good and not evil. 7# May you find forgiveness for yourself and forgive others. 8# May you share freely, never taking more than you give. 9# 10#*********************************************************************** 11# 12# $Id: thread001.test,v 1.7 2009/01/19 17:40:12 drh Exp $ 13 14set testdir [file dirname $argv0] 15 16source $testdir/tester.tcl 17ifcapable !mutex { 18 return 19} 20source $testdir/thread_common.tcl 21if {[info commands sqlthread] eq ""} { 22 return 23} 24 25set ::NTHREAD 10 26 27# Run this test three times: 28# 29# 1) All threads use the same database handle. 30# 2) All threads use their own database handles. 31# 3) All threads use their own database handles, shared-cache is enabled. 32# 33# 34# 35foreach {tn same_db shared_cache} [list \ 36 1 1 0 \ 37 2 0 0 \ 38 3 0 1 \ 39] { 40 # Empty the database. 41 # 42 catchsql { DROP TABLE ab; } 43 44 do_test thread001.$tn.0 { 45 db close 46 sqlite3_enable_shared_cache $shared_cache 47 sqlite3_enable_shared_cache $shared_cache 48 } $shared_cache 49 sqlite3 db test.db -fullmutex 1 50 51 set dbconfig "" 52 if {$same_db} { 53 set dbconfig [list set ::DB [sqlite3_connection_pointer db]] 54 } 55 56 # Set up a database and a schema. The database contains a single 57 # table with two columns. The first column ("a") is an INTEGER PRIMARY 58 # KEY. The second contains the md5sum of all rows in the table with 59 # a smaller value stored in column "a". 60 # 61 do_test thread001.$tn.1 { 62 execsql { 63 CREATE TABLE ab(a INTEGER PRIMARY KEY, b); 64 CREATE INDEX ab_i ON ab(b); 65 INSERT INTO ab SELECT NULL, md5sum(a, b) FROM ab; 66 SELECT count(*) FROM ab; 67 } 68 } {1} 69 do_test thread001.$tn.2 { 70 execsql { 71 SELECT 72 (SELECT md5sum(a, b) FROM ab WHERE a < (SELECT max(a) FROM ab)) == 73 (SELECT b FROM ab WHERE a = (SELECT max(a) FROM ab)) 74 } 75 } {1} 76 do_test thread001.$tn.3 { 77 execsql { PRAGMA integrity_check } 78 } {ok} 79 80 set thread_program { 81 #sqlthread parent {puts STARTING..} 82 set needToClose 0 83 if {![info exists ::DB]} { 84 set ::DB [sqlthread open test.db] 85 #sqlthread parent "puts \"OPEN $::DB\"" 86 set needToClose 1 87 } 88 89 for {set i 0} {$i < 100} {incr i} { 90 # Test that the invariant is true. 91 do_test t1 { 92 execsql { 93 SELECT 94 (SELECT md5sum(a, b) FROM ab WHERE a < (SELECT max(a) FROM ab)) == 95 (SELECT b FROM ab WHERE a = (SELECT max(a) FROM ab)) 96 } 97 } {1} 98 99 # Add another row to the database. 100 execsql { INSERT INTO ab SELECT NULL, md5sum(a, b) FROM ab } 101 } 102 103 if {$needToClose} { 104 #sqlthread parent "puts \"CLOSE $::DB\"" 105 sqlite3_close $::DB 106 } 107 #sqlthread parent "puts \"DONE\"" 108 109 list OK 110 } 111 112 # Kick off $::NTHREAD threads: 113 # 114 array unset finished 115 for {set i 0} {$i < $::NTHREAD} {incr i} { 116 thread_spawn finished($i) $dbconfig $thread_procs $thread_program 117 } 118 119 # Wait for all threads to finish, then check they all returned "OK". 120 # 121 for {set i 0} {$i < $::NTHREAD} {incr i} { 122 if {![info exists finished($i)]} { 123 vwait finished($i) 124 } 125 do_test thread001.$tn.4.$i { 126 set ::finished($i) 127 } OK 128 } 129 130 # Check the database still looks Ok. 131 # 132 do_test thread001.$tn.5 { 133 execsql { SELECT count(*) FROM ab; } 134 } [expr {1 + $::NTHREAD*100}] 135 do_test thread001.$tn.6 { 136 execsql { 137 SELECT 138 (SELECT md5sum(a, b) FROM ab WHERE a < (SELECT max(a) FROM ab)) == 139 (SELECT b FROM ab WHERE a = (SELECT max(a) FROM ab)) 140 } 141 } {1} 142 do_test thread001.$tn.7 { 143 execsql { PRAGMA integrity_check } 144 } {ok} 145} 146 147finish_test 148