| OLD | NEW | 
| (Empty) |  | 
 |    1 # 2001 September 15 | 
 |    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 # This file implements regression tests for SQLite library.  The | 
 |   12 # focus of this file is testing the execution of SQL statements from | 
 |   13 # within callbacks generated by VMs that themselves open statement  | 
 |   14 # transactions. | 
 |   15 # | 
 |   16 # $Id: tkt3718.test,v 1.2 2009/06/05 17:09:12 drh Exp $ | 
 |   17  | 
 |   18 set testdir [file dirname $argv0] | 
 |   19 source $testdir/tester.tcl | 
 |   20  | 
 |   21 do_test tkt3718-1.1 { | 
 |   22   execsql { | 
 |   23     CREATE TABLE t1(a PRIMARY KEY, b); | 
 |   24     INSERT INTO t1 VALUES(1, 'one'); | 
 |   25     INSERT INTO t1 VALUES(2, 'two'); | 
 |   26     INSERT INTO t1 VALUES(3, 'three'); | 
 |   27     INSERT INTO t1 VALUES(4, 'four'); | 
 |   28     INSERT INTO t1 VALUES(5, 'five'); | 
 |   29     CREATE TABLE t2(a PRIMARY KEY, b); | 
 |   30   } | 
 |   31 } {} | 
 |   32  | 
 |   33 # SQL scalar function: | 
 |   34 # | 
 |   35 #   f1(<arg>) | 
 |   36 # | 
 |   37 # Uses database handle [db] to execute "SELECT f2(<arg>)". Returns either | 
 |   38 # the results or error message from the "SELECT f2(<arg>)" query to the | 
 |   39 # caller. | 
 |   40 # | 
 |   41 proc f1 {args} { | 
 |   42   set a [lindex $args 0] | 
 |   43   catch { db eval {SELECT f2($a)} } msg | 
 |   44   set msg | 
 |   45 } | 
 |   46  | 
 |   47 # SQL scalar function: | 
 |   48 # | 
 |   49 #   f2(<arg>) | 
 |   50 # | 
 |   51 # Return the value of <arg>. Unless <arg> is "three", in which case throw | 
 |   52 # an exception. | 
 |   53 # | 
 |   54 proc f2 {args} { | 
 |   55   set a [lindex $args 0] | 
 |   56   if {$a == "three"} { error "Three!!" } | 
 |   57   return $a | 
 |   58 } | 
 |   59  | 
 |   60 db func f1 f1 | 
 |   61 db func f2 f2 | 
 |   62  | 
 |   63 # The second INSERT statement below uses the f1 user function such that | 
 |   64 # half-way through the INSERT operation f1() will run an SQL statement | 
 |   65 # that throws an exception. At one point, before #3718 was fixed, this | 
 |   66 # caused the statement transaction belonging to the INSERT statement to | 
 |   67 # be rolled back. The result was that some (but not all) of the rows that  | 
 |   68 # should have been inserted went missing. | 
 |   69 # | 
 |   70 do_test tkt3718-1.2 { | 
 |   71   execsql { | 
 |   72     BEGIN; | 
 |   73     INSERT INTO t2 SELECT a, b FROM t1; | 
 |   74     INSERT INTO t2 SELECT a+5, f1(b) FROM t1; | 
 |   75     COMMIT; | 
 |   76   } | 
 |   77   execsql { | 
 |   78     SELECT a FROM t2; | 
 |   79   } | 
 |   80 } {1 2 3 4 5 6 7 8 9 10} | 
 |   81  | 
 |   82 # This test turns on the count_changes pragma (causing DML statements to | 
 |   83 # return SQLITE_ROW once, with a single integer result value reporting the | 
 |   84 # number of rows affected by the statement). It then executes an INSERT | 
 |   85 # statement that requires a statement journal. After stepping the statement | 
 |   86 # once, so that it returns SQLITE_ROW, a second SQL statement that throws an | 
 |   87 # exception is run. At one point, before #3718 was fixed, this caused the | 
 |   88 # statement transaction belonging to the INSERT statement to be rolled back. | 
 |   89 # The result was that none of the rows were actually inserted. | 
 |   90 #  | 
 |   91 # | 
 |   92 do_test tkt3718-1.3 { | 
 |   93   execsql {  | 
 |   94     DELETE FROM t2 WHERE a > 5; | 
 |   95     PRAGMA count_changes = 1; | 
 |   96     BEGIN; | 
 |   97   } | 
 |   98   db eval {INSERT INTO t2 SELECT a+5, b||'+5' FROM t1} { | 
 |   99     catch { db eval {SELECT f2('three')} } msg | 
 |  100   } | 
 |  101   execsql { | 
 |  102     COMMIT; | 
 |  103     SELECT a FROM t2; | 
 |  104   } | 
 |  105 } {1 2 3 4 5 6 7 8 9 10} | 
 |  106  | 
 |  107 do_test tkt3718-1.4 { | 
 |  108   execsql {pragma count_changes=0} | 
 |  109 } {} | 
 |  110  | 
 |  111 # This SQL function executes the SQL specified as an argument against | 
 |  112 # database [db]. | 
 |  113 # | 
 |  114 proc sql {doit zSql} { | 
 |  115   if {$doit} { catchsql $zSql } | 
 |  116 } | 
 |  117 db func sql [list sql] | 
 |  118  | 
 |  119 # The following tests, tkt3718-2.*, test that a nested statement  | 
 |  120 # transaction can be successfully committed or reverted without  | 
 |  121 # affecting the parent statement transaction. | 
 |  122 # | 
 |  123 do_test tkt3718-2.1 { | 
 |  124   execsql { SELECT sql(1, 'DELETE FROM t2 WHERE a = '||a ) FROM t2 WHERE a>5 } | 
 |  125   execsql { SELECT a from t2 } | 
 |  126 } {1 2 3 4 5} | 
 |  127 do_test tkt3718-2.2 { | 
 |  128   execsql { | 
 |  129     DELETE FROM t2 WHERE a > 5; | 
 |  130     BEGIN; | 
 |  131     INSERT INTO t2 SELECT a+5, sql(a==3, | 
 |  132         'INSERT INTO t2 SELECT a+10, f2(b) FROM t1' | 
 |  133     ) FROM t1; | 
 |  134   } | 
 |  135   execsql { | 
 |  136     COMMIT; | 
 |  137     SELECT a FROM t2; | 
 |  138   } | 
 |  139 } {1 2 3 4 5 6 7 8 9 10} | 
 |  140 do_test tkt3718-2.3 { | 
 |  141   execsql { | 
 |  142     DELETE FROM t2 WHERE a > 5; | 
 |  143     BEGIN; | 
 |  144     INSERT INTO t2 SELECT a+5, sql(a==3, | 
 |  145         'INSERT INTO t2 SELECT a+10, b FROM t1' | 
 |  146     ) FROM t1; | 
 |  147     COMMIT; | 
 |  148   } | 
 |  149   execsql { SELECT a FROM t2 ORDER BY a+0} | 
 |  150 } {1 2 3 4 5 6 7 8 9 10 11 12 13 14 15} | 
 |  151 integrity_check tkt3718.2-4 | 
 |  152  | 
 |  153 # The next set of tests, tkt3718-3.*, test that a statement transaction | 
 |  154 # that has a committed statement transaction nested inside of it can | 
 |  155 # be committed or reverted. | 
 |  156 # | 
 |  157 foreach {tn io ii results} { | 
 |  158   1 0 10 {1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20} | 
 |  159   2 1 10 {6 7 8 9 10 16 17 18 19 20} | 
 |  160   3 0 11 {1 2 3 4 5 6 7 8 9 10 16 17 18 19 20} | 
 |  161   4 1 11 {6 7 8 9 10 16 17 18 19 20} | 
 |  162 } { | 
 |  163   do_test tkt3718-3.$tn { | 
 |  164     execsql {  | 
 |  165       DELETE FROM t2; | 
 |  166       INSERT INTO t2 SELECT a+5, b FROM t1; | 
 |  167       INSERT INTO t2 SELECT a+15, b FROM t1; | 
 |  168     } | 
 |  169  | 
 |  170     catchsql " | 
 |  171       BEGIN; | 
 |  172       INSERT INTO t2 SELECT a+$io, sql(a==3, | 
 |  173           'INSERT INTO t2 SELECT a+$ii, b FROM t1' | 
 |  174       ) FROM t1; | 
 |  175     " | 
 |  176  | 
 |  177     execsql { COMMIT } | 
 |  178  | 
 |  179     execsql { SELECT a FROM t2 ORDER BY a+0} | 
 |  180   } $results | 
 |  181  | 
 |  182   integrity_check tkt3718-3.$tn.integrity | 
 |  183 } | 
 |  184  | 
 |  185 # This is the same test as tkt3718-3.*, but with 3 levels of nesting. | 
 |  186 # | 
 |  187 foreach {tn i1 i2 i3 results} { | 
 |  188   1   0 10 20   {5 10 15 20 25 30} | 
 |  189   2   0 10 21   {5 10 15 20 30} | 
 |  190   3   0 11 20   {5 10 20 30} | 
 |  191   4   0 11 21   {5 10 20 30} | 
 |  192   5   1 10 20   {10 20 30} | 
 |  193   6   1 10 21   {10 20 30} | 
 |  194   7   1 11 20   {10 20 30} | 
 |  195   8   1 11 21   {10 20 30} | 
 |  196 } { | 
 |  197   do_test tkt3718-4.$tn { | 
 |  198     execsql {  | 
 |  199       DELETE FROM t2; | 
 |  200       INSERT INTO t2 SELECT a+5, b FROM t1; | 
 |  201       INSERT INTO t2 SELECT a+15, b FROM t1; | 
 |  202       INSERT INTO t2 SELECT a+25, b FROM t1; | 
 |  203     } | 
 |  204  | 
 |  205     catchsql " | 
 |  206       BEGIN; | 
 |  207       INSERT INTO t2 SELECT a+$i1, sql(a==3, | 
 |  208           'INSERT INTO t2 SELECT a+$i2, sql(a==3,  | 
 |  209              ''INSERT INTO t2 SELECT a+$i3, b FROM t1'' | 
 |  210            ) FROM t1' | 
 |  211       ) FROM t1; | 
 |  212     " | 
 |  213  | 
 |  214     execsql { COMMIT } | 
 |  215  | 
 |  216     execsql { SELECT a FROM t2 WHERE (a%5)==0 ORDER BY a+0} | 
 |  217   } $results | 
 |  218  | 
 |  219   do_test tkt3718-4.$tn.extra { | 
 |  220     execsql { | 
 |  221       SELECT  | 
 |  222         (SELECT sum(a) FROM t2)==(SELECT sum(a*5-10) FROM t2 WHERE (a%5)==0) | 
 |  223     } | 
 |  224   } {1} | 
 |  225  | 
 |  226   integrity_check tkt3718-4.$tn.integrity | 
 |  227 } | 
 |  228  | 
 |  229  | 
 |  230 finish_test | 
| OLD | NEW |