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.6 2008/10/07 15:25:49 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# 33foreach {tn same_db shared_cache} [list \ 34 1 1 0 \ 35 2 0 0 \ 36 3 0 1 \ 37] { 38 # Empty the database. 39 # 40 catchsql { DROP TABLE ab; } 41 42 do_test thread001.$tn.0 { 43 db close 44 sqlite3_enable_shared_cache $shared_cache 45 sqlite3_enable_shared_cache $shared_cache 46 } $shared_cache 47 sqlite3 db test.db 48 49 set dbconfig "" 50 if {$same_db} { 51 set dbconfig [list set ::DB [sqlite3_connection_pointer db]] 52 } 53 54 # Set up a database and a schema. The database contains a single 55 # table with two columns. The first column ("a") is an INTEGER PRIMARY 56 # KEY. The second contains the md5sum of all rows in the table with 57 # a smaller value stored in column "a". 58 # 59 do_test thread001.$tn.1 { 60 execsql { 61 CREATE TABLE ab(a INTEGER PRIMARY KEY, b); 62 CREATE INDEX ab_i ON ab(b); 63 INSERT INTO ab SELECT NULL, md5sum(a, b) FROM ab; 64 SELECT count(*) FROM ab; 65 } 66 } {1} 67 do_test thread001.$tn.2 { 68 execsql { 69 SELECT 70 (SELECT md5sum(a, b) FROM ab WHERE a < (SELECT max(a) FROM ab)) == 71 (SELECT b FROM ab WHERE a = (SELECT max(a) FROM ab)) 72 } 73 } {1} 74 do_test thread001.$tn.3 { 75 execsql { PRAGMA integrity_check } 76 } {ok} 77 78 set thread_program { 79 set needToClose 0 80 if {![info exists ::DB]} { 81 set ::DB [sqlthread open test.db] 82 set needToClose 1 83 } 84 85 for {set i 0} {$i < 100} {incr i} { 86 # Test that the invariant is true. 87 do_test t1 { 88 execsql { 89 SELECT 90 (SELECT md5sum(a, b) FROM ab WHERE a < (SELECT max(a) FROM ab)) == 91 (SELECT b FROM ab WHERE a = (SELECT max(a) FROM ab)) 92 } 93 } {1} 94 95 # Add another row to the database. 96 execsql { INSERT INTO ab SELECT NULL, md5sum(a, b) FROM ab } 97 } 98 99 if {$needToClose} { 100 sqlite3_close $::DB 101 } 102 103 list OK 104 } 105 106 # Kick off $::NTHREAD threads: 107 # 108 array unset finished 109 for {set i 0} {$i < $::NTHREAD} {incr i} { 110 thread_spawn finished($i) $dbconfig $thread_procs $thread_program 111 } 112 113 # Wait for all threads to finish, then check they all returned "OK". 114 # 115 for {set i 0} {$i < $::NTHREAD} {incr i} { 116 if {![info exists finished($i)]} { 117 vwait finished($i) 118 } 119 do_test thread001.$tn.4.$i { 120 set ::finished($i) 121 } OK 122 } 123 124 # Check the database still looks Ok. 125 # 126 do_test thread001.$tn.5 { 127 execsql { SELECT count(*) FROM ab; } 128 } [expr {1 + $::NTHREAD*100}] 129 do_test thread001.$tn.6 { 130 execsql { 131 SELECT 132 (SELECT md5sum(a, b) FROM ab WHERE a < (SELECT max(a) FROM ab)) == 133 (SELECT b FROM ab WHERE a = (SELECT max(a) FROM ab)) 134 } 135 } {1} 136 do_test thread001.$tn.7 { 137 execsql { PRAGMA integrity_check } 138 } {ok} 139} 140 141finish_test 142