000001 # 2008 June 18 000002 # 000003 # The author disclaims copyright to this source code. In place of 000004 # a legal notice, here is a blessing: 000005 # 000006 # May you do good and not evil. 000007 # May you find forgiveness for yourself and forgive others. 000008 # May you share freely, never taking more than you give. 000009 # 000010 #*********************************************************************** 000011 # This file implements regression tests for SQLite library. 000012 # 000013 # This file is devoted to testing the sqlite3_next_stmt and 000014 # sqlite3_stmt_readonly and sqlite3_stmt_busy interfaces. 000015 # 000016 # $Id: capi3d.test,v 1.2 2008/07/14 15:11:20 drh Exp $ 000017 # 000018 000019 set testdir [file dirname $argv0] 000020 source $testdir/tester.tcl 000021 000022 # Create N prepared statements against database connection db 000023 # and return a list of all the generated prepared statements. 000024 # 000025 proc make_prepared_statements {N} { 000026 set plist {} 000027 for {set i 0} {$i<$N} {incr i} { 000028 set sql "SELECT $i FROM sqlite_master WHERE name LIKE '%$i%'" 000029 if {rand()<0.33} { 000030 set s [sqlite3_prepare_v2 db $sql -1 notused] 000031 } else { 000032 ifcapable utf16 { 000033 if {rand()<0.5} { 000034 set sql [encoding convertto unicode $sql]\x00\x00 000035 set s [sqlite3_prepare16 db $sql -1 notused] 000036 } else { 000037 set s [sqlite3_prepare db $sql -1 notused] 000038 } 000039 } 000040 ifcapable !utf16 { 000041 set s [sqlite3_prepare db $sql -1 notused] 000042 } 000043 } 000044 lappend plist $s 000045 } 000046 return $plist 000047 } 000048 000049 000050 # Scramble the $inlist into a random order. 000051 # 000052 proc scramble {inlist} { 000053 set y {} 000054 foreach x $inlist { 000055 lappend y [list [expr {rand()}] $x] 000056 } 000057 set y [lsort $y] 000058 set outlist {} 000059 foreach x $y { 000060 lappend outlist [lindex $x 1] 000061 } 000062 return $outlist 000063 } 000064 000065 # Database initially has no prepared statements. 000066 # 000067 do_test capi3d-1.1 { 000068 db cache flush 000069 sqlite3_next_stmt db 0 000070 } {} 000071 000072 # Run the following tests for between 1 and 100 prepared statements. 000073 # 000074 for {set i 1} {$i<=100} {incr i} { 000075 set stmtlist [make_prepared_statements $i] 000076 do_test capi3d-1.2.$i.1 { 000077 set p [sqlite3_next_stmt db 0] 000078 set x {} 000079 while {$p!=""} { 000080 lappend x $p 000081 set p [sqlite3_next_stmt db $p] 000082 } 000083 lsort $x 000084 } [lsort $stmtlist] 000085 do_test capi3-1.2.$i.2 { 000086 foreach p [scramble $::stmtlist] { 000087 sqlite3_finalize $p 000088 } 000089 sqlite3_next_stmt db 0 000090 } {} 000091 } 000092 000093 # Tests for the is-read-only interface. 000094 # 000095 proc test_is_readonly {testname sql truth} { 000096 do_test $testname [format { 000097 set DB [sqlite3_connection_pointer db] 000098 set STMT [sqlite3_prepare $DB {%s} -1 TAIL] 000099 set rc [sqlite3_stmt_readonly $STMT] 000100 sqlite3_finalize $STMT 000101 set rc 000102 } $sql] $truth 000103 000104 # EVIDENCE-OF: R-61212-30018 If prepared statement X is an EXPLAIN or 000105 # EXPLAIN QUERY PLAN statement, then sqlite3_stmt_readonly(X) returns 000106 # the same value as if the EXPLAIN or EXPLAIN QUERY PLAN prefix were 000107 # omitted. 000108 # 000109 do_test $testname.explain [format { 000110 set DB [sqlite3_connection_pointer db] 000111 set STMT [sqlite3_prepare $DB {EXPLAIN %s} -1 TAIL] 000112 set rc [sqlite3_stmt_readonly $STMT] 000113 sqlite3_finalize $STMT 000114 set rc 000115 } $sql] $truth 000116 do_test $testname.eqp [format { 000117 set DB [sqlite3_connection_pointer db] 000118 set STMT [sqlite3_prepare $DB {EXPLAIN QUERY PLAN %s} -1 TAIL] 000119 set rc [sqlite3_stmt_readonly $STMT] 000120 sqlite3_finalize $STMT 000121 set rc 000122 } $sql] $truth 000123 } 000124 000125 # EVIDENCE-OF: R-23332-64992 The sqlite3_stmt_readonly(X) interface 000126 # returns true (non-zero) if and only if the prepared statement X makes 000127 # no direct changes to the content of the database file. 000128 # 000129 test_is_readonly capi3d-2.1 {SELECT * FROM sqlite_master} 1 000130 test_is_readonly capi3d-2.2 {CREATE TABLE t1(x)} 0 000131 db eval {CREATE TABLE t1(x)} 000132 test_is_readonly capi3d-2.3 {INSERT INTO t1 VALUES(5)} 0 000133 test_is_readonly capi3d-2.4 {UPDATE t1 SET x=x+1 WHERE x<0} 0 000134 test_is_readonly capi3d-2.5 {SELECT * FROM t1} 1 000135 ifcapable wal { 000136 test_is_readonly capi3d-2.6 {PRAGMA journal_mode=WAL} 0 000137 test_is_readonly capi3d-2.7 {PRAGMA wal_checkpoint} 0 000138 } 000139 test_is_readonly capi3d-2.8 {PRAGMA application_id=1234} 0 000140 test_is_readonly capi3d-2.9 {VACUUM} 0 000141 test_is_readonly capi3d-2.10 {PRAGMA integrity_check} 1 000142 do_test capi3-2.49 { 000143 sqlite3_stmt_readonly 0 000144 } 1 000145 000146 000147 # EVIDENCE-OF: R-04929-09147 This routine returns false if there is any 000148 # possibility that the statement might change the database file. 000149 # 000150 # EVIDENCE-OF: R-13288-53765 A false return does not guarantee that the 000151 # statement will change the database file. 000152 # 000153 # EVIDENCE-OF: R-22182-18548 For example, an UPDATE statement might have 000154 # a WHERE clause that makes it a no-op, but the sqlite3_stmt_readonly() 000155 # result would still be false. 000156 # 000157 # EVIDENCE-OF: R-50998-48593 Similarly, a CREATE TABLE IF NOT EXISTS 000158 # statement is a read-only no-op if the table already exists, but 000159 # sqlite3_stmt_readonly() still returns false for such a statement. 000160 # 000161 db eval { 000162 CREATE TABLE t2(a,b,c); 000163 INSERT INTO t2 VALUES(1,2,3); 000164 } 000165 test_is_readonly capi3d-2.11 {UPDATE t2 SET a=a+1 WHERE false} 0 000166 test_is_readonly capi3d-2.12 {CREATE TABLE IF NOT EXISTS t2(x,y)} 0 000167 000168 000169 # EVIDENCE-OF: R-37014-01401 The ATTACH and DETACH statements also cause 000170 # sqlite3_stmt_readonly() to return true since, while those statements 000171 # change the configuration of a database connection, they do not make 000172 # changes to the content of the database files on disk. 000173 # 000174 test_is_readonly capi3d-2.13 {ATTACH ':memory:' AS mem1} 1 000175 db eval {ATTACH ':memory:' AS mem1} 000176 test_is_readonly capi3d-2.14 {DETACH mem1} 1 000177 db eval {DETACH mem1} 000178 000179 # EVIDENCE-OF: R-07474-04783 Transaction control statements such as 000180 # BEGIN, COMMIT, ROLLBACK, SAVEPOINT, and RELEASE cause 000181 # sqlite3_stmt_readonly() to return true, since the statements 000182 # themselves do not actually modify the database but rather they control 000183 # the timing of when other statements modify the database. 000184 # 000185 test_is_readonly capi3d-2.15 {BEGIN} 1 000186 test_is_readonly capi3d-2.16 {COMMIT} 1 000187 test_is_readonly capi3d-2.17 {SAVEPOINT one} 1 000188 test_is_readonly capi3d-2.18 {RELEASE one} 1 000189 000190 # EVIDENCE-OF: R-36961-63052 The sqlite3_stmt_readonly() interface 000191 # returns true for BEGIN since BEGIN merely sets internal flags, but the 000192 # BEGIN IMMEDIATE and BEGIN EXCLUSIVE commands do touch the database and 000193 # so sqlite3_stmt_readonly() returns false for those commands. 000194 # 000195 test_is_readonly capi3d-2.19 {BEGIN IMMEDIATE} 0 000196 test_is_readonly capi3d-2.20 {BEGIN EXCLUSIVE} 0 000197 000198 # EVIDENCE-OF: R-21769-42523 For example, if an application defines a 000199 # function "eval()" that calls sqlite3_exec(), then the following SQL 000200 # statement would change the database file through side-effects: SELECT 000201 # eval('DELETE FROM t1') FROM t2; But because the SELECT statement does 000202 # not change the database file directly, sqlite3_stmt_readonly() would 000203 # still return true. 000204 # 000205 proc evalsql {sql} {db eval $sql} 000206 db func eval evalsql 000207 test_is_readonly capi3d-2.21 {SELECT eval('DELETE FROM t1') FROM t2} 1 000208 000209 # Tests for the is-explain interface. 000210 # 000211 proc test_is_explain {testname sql truth} { 000212 do_test $testname [format { 000213 set DB [sqlite3_connection_pointer db] 000214 set STMT [sqlite3_prepare $DB {%s} -1 TAIL] 000215 set rc [sqlite3_stmt_isexplain $STMT] 000216 sqlite3_finalize $STMT 000217 set rc 000218 } $sql] $truth 000219 } 000220 000221 test_is_explain capi3d-2.51 {SELECT * FROM sqlite_master} 0 000222 test_is_explain capi3d-2.52 { explain SELECT * FROM sqlite_master} 1 000223 test_is_explain capi3d-2.53 { Explain Query Plan select * FROM sqlite_master} 2 000224 do_test capi3-2.99 { 000225 sqlite3_stmt_isexplain 0 000226 } 0 000227 000228 # Tests for sqlite3_stmt_busy 000229 # 000230 do_test capi3d-3.1 { 000231 db eval {INSERT INTO t1 VALUES(6); INSERT INTO t1 VALUES(7);} 000232 set STMT [sqlite3_prepare db {SELECT * FROM t1} -1 TAIL] 000233 sqlite3_stmt_busy $STMT 000234 } {0} 000235 do_test capi3d-3.2 { 000236 sqlite3_step $STMT 000237 sqlite3_stmt_busy $STMT 000238 } {1} 000239 do_test capi3d-3.3 { 000240 sqlite3_step $STMT 000241 sqlite3_stmt_busy $STMT 000242 } {1} 000243 do_test capi3d-3.4 { 000244 sqlite3_reset $STMT 000245 sqlite3_stmt_busy $STMT 000246 } {0} 000247 000248 do_test capi3d-3.99 { 000249 sqlite3_finalize $STMT 000250 sqlite3_stmt_busy 0 000251 } {0} 000252 000253 #-------------------------------------------------------------------------- 000254 # Test the sqlite3_stmt_busy() function with ROLLBACK statements. 000255 # 000256 reset_db 000257 000258 do_execsql_test capi3d-4.1 { 000259 CREATE TABLE t4(x,y); 000260 BEGIN; 000261 } 000262 000263 do_test capi3d-4.2.1 { 000264 set ::s1 [sqlite3_prepare_v2 db "ROLLBACK" -1 notused] 000265 sqlite3_step $::s1 000266 } {SQLITE_DONE} 000267 000268 do_test capi3d-4.2.2 { 000269 sqlite3_stmt_busy $::s1 000270 } {0} 000271 000272 do_catchsql_test capi3d-4.2.3 { 000273 VACUUM 000274 } {0 {}} 000275 000276 do_test capi3d-4.2.4 { 000277 sqlite3_reset $::s1 000278 } {SQLITE_OK} 000279 000280 do_catchsql_test capi3d-4.2.5 { 000281 VACUUM 000282 } {0 {}} 000283 000284 do_test capi3d-4.2.6 { 000285 sqlite3_finalize $::s1 000286 } {SQLITE_OK} 000287 000288 000289 finish_test