github.com/jdgcs/sqlite3@v1.12.1-0.20210908114423-bc5f96e4dd51/testdata/tcl/savepoint6.test (about)

     1  # 2009 January 3
     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: savepoint6.test,v 1.4 2009/06/05 17:09:12 drh Exp $
    13  
    14  set testdir [file dirname $argv0]
    15  source $testdir/tester.tcl
    16  
    17  proc sql {zSql} {
    18    uplevel db eval [list $zSql]
    19    #puts stderr "$zSql ;"
    20  }
    21  
    22  set DATABASE_SCHEMA {
    23      PRAGMA auto_vacuum = incremental;
    24      CREATE TABLE t1(x, y);
    25      CREATE UNIQUE INDEX i1 ON t1(x);
    26      CREATE INDEX i2 ON t1(y);
    27  }
    28  
    29  if {0==[info exists ::G(savepoint6_iterations)]} {
    30    set ::G(savepoint6_iterations) 1000
    31  }
    32  
    33  #--------------------------------------------------------------------------
    34  # In memory database state.
    35  #
    36  # ::lSavepoint is a list containing one entry for each active savepoint. The
    37  # first entry in the list corresponds to the most recently opened savepoint.
    38  # Each entry consists of two elements:
    39  #
    40  #   1. The savepoint name.
    41  #
    42  #   2. A serialized Tcl array representing the contents of table t1 at the
    43  #      start of the savepoint. The keys of the array are the x values. The
    44  #      values are the y values.
    45  #  
    46  # Array ::aEntry contains the contents of database table t1. Array keys are
    47  # x values, the array data values are y values.
    48  #
    49  set lSavepoint [list]
    50  array set aEntry [list]
    51  
    52  proc x_to_y {x} {
    53    set nChar [expr int(rand()*250) + 250]
    54    set str " $nChar [string repeat $x. $nChar]"
    55    string range $str 1 $nChar
    56  }
    57  #--------------------------------------------------------------------------
    58  
    59  #-------------------------------------------------------------------------
    60  # Procs to operate on database:
    61  #
    62  #   savepoint NAME
    63  #   rollback  NAME
    64  #   release   NAME
    65  #
    66  #   insert_rows XVALUES
    67  #   delete_rows XVALUES
    68  #
    69  proc savepoint {zName} {
    70    catch { sql "SAVEPOINT $zName" }
    71    lappend ::lSavepoint [list $zName [array get ::aEntry]]
    72  }
    73  
    74  proc rollback {zName} {
    75    catch { sql "ROLLBACK TO $zName" }
    76    for {set i [expr {[llength $::lSavepoint]-1}]} {$i>=0} {incr i -1} {
    77      set zSavepoint [lindex $::lSavepoint $i 0]
    78      if {$zSavepoint eq $zName} {
    79        unset -nocomplain ::aEntry
    80        array set ::aEntry [lindex $::lSavepoint $i 1]
    81  
    82  
    83        if {$i+1 < [llength $::lSavepoint]} {
    84          set ::lSavepoint [lreplace $::lSavepoint [expr $i+1] end]
    85        }
    86        break
    87      }
    88    }
    89  }
    90  
    91  proc release {zName} {
    92    catch { sql "RELEASE $zName" }
    93    for {set i [expr {[llength $::lSavepoint]-1}]} {$i>=0} {incr i -1} {
    94      set zSavepoint [lindex $::lSavepoint $i 0]
    95      if {$zSavepoint eq $zName} {
    96        set ::lSavepoint [lreplace $::lSavepoint $i end]
    97        break
    98      }
    99    }
   100  
   101    if {[llength $::lSavepoint] == 0} {
   102      #puts stderr "-- End of transaction!!!!!!!!!!!!!"
   103    }
   104  }
   105  
   106  proc insert_rows {lX} {
   107    foreach x $lX {
   108      set y [x_to_y $x]
   109  
   110      # Update database [db]
   111      sql "INSERT OR REPLACE INTO t1 VALUES($x, '$y')"
   112  
   113      # Update the Tcl database.
   114      set ::aEntry($x) $y
   115    }
   116  }
   117  
   118  proc delete_rows {lX} {
   119    foreach x $lX {
   120      # Update database [db]
   121      sql "DELETE FROM t1 WHERE x = $x"
   122  
   123      # Update the Tcl database.
   124      unset -nocomplain ::aEntry($x)
   125    }
   126  }
   127  #-------------------------------------------------------------------------
   128  
   129  #-------------------------------------------------------------------------
   130  # Proc to compare database content with the in-memory representation.
   131  #
   132  #   checkdb
   133  #
   134  proc checkdb {} {
   135    set nEntry [db one {SELECT count(*) FROM t1}]
   136    set nEntry2 [array size ::aEntry]
   137    if {$nEntry != $nEntry2} {
   138      error "$nEntry entries in database, $nEntry2 entries in array"
   139    }
   140    db eval {SELECT x, y FROM t1} {
   141      if {![info exists ::aEntry($x)]} {
   142        error "Entry $x exists in database, but not in array"
   143      }
   144      if {$::aEntry($x) ne $y} {
   145        error "Entry $x is set to {$y} in database, {$::aEntry($x)} in array"
   146      }
   147    }
   148  
   149    db eval { PRAGMA integrity_check }
   150  }
   151  #-------------------------------------------------------------------------
   152  
   153  #-------------------------------------------------------------------------
   154  # Proc to return random set of x values.
   155  #
   156  #   random_integers
   157  #
   158  proc random_integers {nRes nRange} {
   159    set ret [list]
   160    for {set i 0} {$i<$nRes} {incr i} {
   161      lappend ret [expr int(rand()*$nRange)]
   162    }
   163    return $ret
   164  } 
   165  #-------------------------------------------------------------------------
   166  
   167  proc database_op {} {
   168    set i [expr int(rand()*2)] 
   169    if {$i==0} {
   170      insert_rows [random_integers 100 1000]
   171    }
   172    if {$i==1} {
   173      delete_rows [random_integers 100 1000]
   174      set i [expr int(rand()*3)] 
   175      if {$i==0} {
   176        sql {PRAGMA incremental_vacuum}
   177      }
   178    }
   179  }
   180  
   181  proc savepoint_op {} {
   182    set names {one two three four five}
   183    set cmds  {savepoint savepoint savepoint savepoint release rollback}
   184  
   185    set C [lindex $cmds [expr int(rand()*6)]]
   186    set N [lindex $names [expr int(rand()*5)]]
   187  
   188    #puts stderr "   $C $N ;  "
   189    #flush stderr
   190  
   191    $C $N
   192    return ok
   193  }
   194  
   195  expr srand(0)
   196  
   197  ############################################################################
   198  ############################################################################
   199  # Start of test cases.
   200  
   201  do_test savepoint6-1.1 {
   202    sql $DATABASE_SCHEMA
   203  } {}
   204  do_test savepoint6-1.2 {
   205    insert_rows {
   206      497 166 230 355 779 588 394 317 290 475 362 193 805 851 564 
   207      763 44 930 389 819 765 760 966 280 538 414 500 18 25 287 320 
   208      30 382 751 87 283 981 429 630 974 421 270 810 405 
   209    }
   210  
   211    savepoint one
   212    insert_rows 858
   213    delete_rows 930
   214    savepoint two
   215      execsql {PRAGMA incremental_vacuum}
   216      savepoint three
   217        insert_rows 144
   218       rollback three
   219      rollback two
   220    release one
   221  
   222    execsql {SELECT count(*) FROM t1}
   223  } {44}
   224  
   225  foreach zSetup [list {
   226    set testname normal
   227    sqlite3 db test.db
   228  } {
   229    if {[wal_is_wal_mode]} continue
   230    set testname tempdb
   231    sqlite3 db ""
   232  } {
   233    if {[permutation] eq "journaltest"} {
   234      continue
   235    }
   236    set testname nosync
   237    sqlite3 db test.db
   238    sql { PRAGMA synchronous = off }
   239  } {
   240    set testname smallcache
   241    sqlite3 db test.db
   242    sql { PRAGMA cache_size = 10 }
   243  }] {
   244  
   245    unset -nocomplain ::lSavepoint
   246    unset -nocomplain ::aEntry
   247  
   248    catch { db close }
   249    forcedelete test.db test.db-wal test.db-journal
   250    eval $zSetup
   251    sql $DATABASE_SCHEMA
   252  
   253    wal_set_journal_mode
   254  
   255    do_test savepoint6-$testname.setup {
   256      savepoint one
   257      insert_rows [random_integers 100 1000]
   258      release one
   259      checkdb
   260    } {ok}
   261    
   262    for {set i 0} {$i < $::G(savepoint6_iterations)} {incr i} {
   263      do_test savepoint6-$testname.$i.1 {
   264        savepoint_op
   265        checkdb
   266      } {ok}
   267    
   268      do_test savepoint6-$testname.$i.2 {
   269        database_op
   270        database_op
   271        checkdb
   272      } {ok}
   273    }
   274  
   275    wal_check_journal_mode savepoint6-$testname.walok
   276  }
   277  
   278  unset -nocomplain ::lSavepoint
   279  unset -nocomplain ::aEntry
   280  
   281  finish_test