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