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

     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