modernc.org/cc@v1.0.1/v2/testdata/_sqlite/ext/session/session2.test (about)

     1  # 2011 Mar 16
     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  # The focus of this file is testing the session module.
    13  #
    14  
    15  if {![info exists testdir]} {
    16    set testdir [file join [file dirname [info script]] .. .. test]
    17  } 
    18  source [file join [file dirname [info script]] session_common.tcl]
    19  source $testdir/tester.tcl
    20  ifcapable !session {finish_test; return}
    21  
    22  set testprefix session2
    23  
    24  proc test_reset {} {
    25    catch { db close }
    26    catch { db2 close }
    27    forcedelete test.db test.db2
    28    sqlite3 db test.db
    29    sqlite3 db2 test.db2
    30  }
    31  
    32  ##########################################################################
    33  # End of proc definitions. Start of tests.
    34  ##########################################################################
    35  
    36  test_reset
    37  do_execsql_test 1.0 { 
    38    CREATE TABLE t1(a PRIMARY KEY, b);
    39    INSERT INTO t1 VALUES('i', 'one');
    40  }
    41  do_iterator_test 1.1 t1 {
    42    DELETE FROM t1 WHERE a = 'i';
    43    INSERT INTO t1 VALUES('ii', 'two');
    44  } {
    45    {DELETE t1 0 X. {t i t one} {}} 
    46    {INSERT t1 0 X. {} {t ii t two}}
    47  }
    48  
    49  do_iterator_test 1.2 t1 {
    50    INSERT INTO t1 VALUES(1.5, 99.9)
    51  } {
    52    {INSERT t1 0 X. {} {f 1.5 f 99.9}}
    53  }
    54  
    55  do_iterator_test 1.3 t1 {
    56    UPDATE t1 SET b = 100.1 WHERE a = 1.5;
    57    UPDATE t1 SET b = 99.9 WHERE a = 1.5;
    58  } { }
    59  
    60  do_iterator_test 1.4 t1 {
    61    UPDATE t1 SET b = 100.1 WHERE a = 1.5;
    62  } {
    63    {UPDATE t1 0 X. {f 1.5 f 99.9} {{} {} f 100.1}}
    64  }
    65  
    66  
    67  # Execute each of the following blocks of SQL on database [db1]. Collect
    68  # changes using a session object. Apply the resulting changeset to
    69  # database [db2]. Then check that the contents of the two databases are
    70  # identical.
    71  #
    72  
    73  set set_of_tests {
    74    1 { INSERT INTO %T1% VALUES(1, 2) } 
    75  
    76    2 {
    77      INSERT INTO %T2% VALUES(1, NULL);
    78      INSERT INTO %T2% VALUES(2, NULL);
    79      INSERT INTO %T2% VALUES(3, NULL);
    80      DELETE FROM %T2% WHERE a = 2;
    81      INSERT INTO %T2% VALUES(4, NULL);
    82      UPDATE %T2% SET b=0 WHERE b=1;
    83    } 
    84  
    85    3 { INSERT INTO %T3% SELECT *, NULL FROM %T2% }
    86  
    87    4 {
    88      INSERT INTO %T3% SELECT a||a, b||b, NULL FROM %T3%;
    89      DELETE FROM %T3% WHERE rowid%2;
    90    }
    91  
    92    5 { UPDATE %T3% SET c = a||b }
    93  
    94    6 { UPDATE %T1% SET a = 32 }
    95  
    96    7 { 
    97      INSERT INTO %T1% SELECT randomblob(32), randomblob(32) FROM %T1%; 
    98      INSERT INTO %T1% SELECT randomblob(32), randomblob(32) FROM %T1%; 
    99      INSERT INTO %T1% SELECT randomblob(32), randomblob(32) FROM %T1%; 
   100      INSERT INTO %T1% SELECT randomblob(32), randomblob(32) FROM %T1%; 
   101      INSERT INTO %T1% SELECT randomblob(32), randomblob(32) FROM %T1%; 
   102      INSERT INTO %T1% SELECT randomblob(32), randomblob(32) FROM %T1%; 
   103      INSERT INTO %T1% SELECT randomblob(32), randomblob(32) FROM %T1%; 
   104      INSERT INTO %T1% SELECT randomblob(32), randomblob(32) FROM %T1%; 
   105      INSERT INTO %T1% SELECT randomblob(32), randomblob(32) FROM %T1%; 
   106      INSERT INTO %T1% SELECT randomblob(32), randomblob(32) FROM %T1%; 
   107      INSERT INTO %T1% SELECT randomblob(32), randomblob(32) FROM %T1%; 
   108      DELETE FROM %T1% WHERE (rowid%3)==0;
   109    }
   110  
   111    8 {
   112      BEGIN;
   113        INSERT INTO %T1% SELECT randomblob(32), randomblob(32) FROM %T1%;
   114      ROLLBACK;
   115    }
   116    9 {
   117      BEGIN;
   118        UPDATE %T1% SET b = 'xxx';
   119      ROLLBACK;
   120    }
   121    10 {
   122      BEGIN;
   123        DELETE FROM %T1% WHERE 1;
   124      ROLLBACK;
   125    }
   126    11 {
   127      INSERT INTO %T1% VALUES(randomblob(21000), randomblob(0));
   128      INSERT INTO %T1% VALUES(1.5, 1.5);
   129      INSERT INTO %T1% VALUES(4.56, -99.999999999999999999999);
   130    }
   131    12 {
   132      INSERT INTO %T2% VALUES(NULL, NULL);
   133    }
   134  
   135    13 {
   136      DELETE FROM %T1% WHERE 1;
   137  
   138      -- Insert many rows with real primary keys. Enough to force the session
   139      -- objects hash table to resize. 
   140      INSERT INTO %T1% VALUES(0.1, 0.1);
   141      INSERT INTO %T1% SELECT a+0.1, b+0.1 FROM %T1%;
   142      INSERT INTO %T1% SELECT a+0.2, b+0.2 FROM %T1%;
   143      INSERT INTO %T1% SELECT a+0.4, b+0.4 FROM %T1%;
   144      INSERT INTO %T1% SELECT a+0.8, b+0.8 FROM %T1%;
   145      INSERT INTO %T1% SELECT a+1.6, b+1.6 FROM %T1%;
   146      INSERT INTO %T1% SELECT a+3.2, b+3.2 FROM %T1%;
   147      INSERT INTO %T1% SELECT a+6.4, b+6.4 FROM %T1%;
   148      INSERT INTO %T1% SELECT a+12.8, b+12.8 FROM %T1%;
   149      INSERT INTO %T1% SELECT a+25.6, b+25.6 FROM %T1%;
   150      INSERT INTO %T1% SELECT a+51.2, b+51.2 FROM %T1%;
   151      INSERT INTO %T1% SELECT a+102.4, b+102.4 FROM %T1%;
   152      INSERT INTO %T1% SELECT a+204.8, b+204.8 FROM %T1%;
   153    }
   154  
   155    14 {
   156      DELETE FROM %T1% WHERE 1;
   157    }
   158  
   159    15 {
   160      INSERT INTO %T1% VALUES(1, 1);
   161      INSERT INTO %T1% SELECT a+2, b+2 FROM %T1%;
   162      INSERT INTO %T1% SELECT a+4, b+4 FROM %T1%;
   163      INSERT INTO %T1% SELECT a+8, b+8 FROM %T1%;
   164      INSERT INTO %T1% SELECT a+256, b+256 FROM %T1%;
   165    }
   166  
   167    16 {
   168      INSERT INTO %T4% VALUES('abc', 'def');
   169      INSERT INTO %T4% VALUES('def', 'abc');
   170    }
   171    17 { UPDATE %T4% SET b = 1 }
   172  
   173    18 { DELETE FROM %T4% WHERE 1 }
   174  
   175    19 { 
   176      INSERT INTO t1 VALUES('', '');
   177      INSERT INTO t1 VALUES(X'', X'');
   178    }
   179    20 { 
   180      DELETE FROM t1;
   181      INSERT INTO t1 VALUES('', NULL);
   182    }
   183  }
   184  
   185  test_reset
   186  do_common_sql {
   187    CREATE TABLE t1(a PRIMARY KEY, b);
   188    CREATE TABLE t2(a, b INTEGER PRIMARY KEY);
   189    CREATE TABLE t3(a, b, c, PRIMARY KEY(a, b));
   190    CREATE TABLE t4(a, b, PRIMARY KEY(b, a));
   191  }
   192  
   193  foreach {tn sql} [string map {%T1% t1 %T2% t2 %T3% t3 %T4% t4} $set_of_tests] {
   194    do_then_apply_sql $sql
   195    do_test 2.$tn { compare_db db db2 } {}
   196  }
   197  
   198  # The following block of tests is similar to the last, except that the
   199  # session object is recording changes made to an attached database. The
   200  # main database contains a table of the same name as the table being
   201  # modified within the attached db.
   202  #
   203  test_reset
   204  forcedelete test.db3
   205  sqlite3 db3 test.db3
   206  do_test 3.0 {
   207    execsql {
   208      ATTACH 'test.db3' AS 'aux';
   209      CREATE TABLE t1(a, b PRIMARY KEY);
   210      CREATE TABLE t2(x, y, z);
   211      CREATE TABLE t3(a);
   212  
   213      CREATE TABLE aux.t1(a PRIMARY KEY, b);
   214      CREATE TABLE aux.t2(a, b INTEGER PRIMARY KEY);
   215      CREATE TABLE aux.t3(a, b, c, PRIMARY KEY(a, b));
   216      CREATE TABLE aux.t4(a, b, PRIMARY KEY(b, a));
   217    }
   218    execsql {
   219      CREATE TABLE t1(a PRIMARY KEY, b);
   220      CREATE TABLE t2(a, b INTEGER PRIMARY KEY);
   221      CREATE TABLE t3(a, b, c, PRIMARY KEY(a, b));
   222      CREATE TABLE t4(a, b, PRIMARY KEY(b, a));
   223    } db2
   224  } {}
   225  
   226  proc xTrace {args} { puts $args }
   227  
   228  foreach {tn sql} [
   229    string map {%T1% aux.t1 %T2% aux.t2 %T3% aux.t3 %T4% aux.t4} $set_of_tests
   230  ] {
   231    do_then_apply_sql $sql aux
   232    do_test 3.$tn { compare_db db2 db3 } {}
   233  }
   234  catch {db3 close}
   235  
   236  
   237  #-------------------------------------------------------------------------
   238  # The following tests verify that NULL values in primary key columns are
   239  # handled correctly by the session module.
   240  #
   241  test_reset
   242  do_execsql_test 4.0 {
   243    CREATE TABLE t1(a PRIMARY KEY);
   244    CREATE TABLE t2(a, b, c, PRIMARY KEY(c, b));
   245    CREATE TABLE t3(a, b INTEGER PRIMARY KEY);
   246  }
   247  
   248  foreach {tn sql changeset} {
   249    1 {
   250      INSERT INTO t1 VALUES(123);
   251      INSERT INTO t1 VALUES(NULL);
   252      INSERT INTO t1 VALUES(456);
   253    } {
   254      {INSERT t1 0 X {} {i 456}} 
   255      {INSERT t1 0 X {} {i 123}}
   256    }
   257  
   258    2 {
   259      UPDATE t1 SET a = NULL;
   260    } {
   261      {DELETE t1 0 X {i 456} {}}
   262      {DELETE t1 0 X {i 123} {}}
   263    }
   264  
   265    3 { DELETE FROM t1 } { }
   266  
   267    4 { 
   268      INSERT INTO t3 VALUES(NULL, NULL)
   269    } {
   270      {INSERT t3 0 .X {} {n {} i 1}} 
   271    }
   272  
   273    5 { INSERT INTO t2 VALUES(1, 2, NULL) }    { }
   274    6 { INSERT INTO t2 VALUES(1, NULL, 3) }    { }
   275    7 { INSERT INTO t2 VALUES(1, NULL, NULL) } { }
   276    8 { INSERT INTO t2 VALUES(1, 2, 3) }    { {INSERT t2 0 .XX {} {i 1 i 2 i 3}} }
   277    9 { DELETE FROM t2 WHERE 1 }            { {DELETE t2 0 .XX {i 1 i 2 i 3} {}} }
   278  
   279  } {
   280    do_iterator_test 4.$tn {t1 t2 t3} $sql $changeset
   281  }
   282  
   283  
   284  #-------------------------------------------------------------------------
   285  # Test that if NULL is passed to sqlite3session_attach(), all database
   286  # tables are attached to the session object.
   287  #
   288  test_reset
   289  do_execsql_test 5.0 {
   290    CREATE TABLE t1(a PRIMARY KEY);
   291    CREATE TABLE t2(x, y PRIMARY KEY);
   292  }
   293  
   294  foreach {tn sql changeset} {
   295    1 { INSERT INTO t1 VALUES(35) }     { {INSERT t1 0 X {} {i 35}} }
   296    2 { INSERT INTO t2 VALUES(36, 37) } { {INSERT t2 0 .X {} {i 36 i 37}} }
   297    3 { 
   298      DELETE FROM t1 WHERE 1;
   299      UPDATE t2 SET x = 34;
   300    } { 
   301      {DELETE t1 0 X {i 35} {}}
   302      {UPDATE t2 0 .X {i 36 i 37} {i 34 {} {}}}
   303    }
   304  } {
   305    do_iterator_test 5.$tn * $sql $changeset
   306  }
   307  
   308  #-------------------------------------------------------------------------
   309  # The next block of tests verify that the "indirect" flag is set 
   310  # correctly within changesets. The indirect flag is set for a change
   311  # if either of the following are true:
   312  #
   313  #   * The sqlite3session_indirect() API has been used to set the session
   314  #     indirect flag to true, or
   315  #   * The change was made by a trigger.
   316  #
   317  # If the same row is updated more than once during a session, then the 
   318  # change is considered indirect only if all changes meet the criteria 
   319  # above.
   320  #
   321  test_reset
   322  db function indirect [list S indirect]
   323  
   324  do_execsql_test 6.0 {
   325    CREATE TABLE t1(a PRIMARY KEY, b, c);
   326  
   327    CREATE TABLE t2(x PRIMARY KEY, y);
   328    CREATE TRIGGER AFTER INSERT ON t2 WHEN new.x%2 BEGIN
   329      INSERT INTO t2 VALUES(new.x+1, NULL);
   330    END;
   331  }
   332  
   333  do_iterator_test 6.1.1 * {
   334    INSERT INTO t1 VALUES(1, 'one', 'i');
   335    SELECT indirect(1);
   336    INSERT INTO t1 VALUES(2, 'two', 'ii');
   337    SELECT indirect(0);
   338    INSERT INTO t1 VALUES(3, 'three', 'iii');
   339  } {
   340    {INSERT t1 0 X.. {} {i 1 t one t i}}
   341    {INSERT t1 1 X.. {} {i 2 t two t ii}}
   342    {INSERT t1 0 X.. {} {i 3 t three t iii}}
   343  }
   344  
   345  do_iterator_test 6.1.2 * {
   346    SELECT indirect(1);
   347    UPDATE t1 SET c = 'I' WHERE a = 1;
   348    SELECT indirect(0);
   349  } {
   350    {UPDATE t1 1 X.. {i 1 {} {} t i} {{} {} {} {} t I}}
   351  }
   352  do_iterator_test 6.1.3 * {
   353    SELECT indirect(1);
   354    UPDATE t1 SET c = '.' WHERE a = 1;
   355    SELECT indirect(0);
   356    UPDATE t1 SET c = 'o' WHERE a = 1;
   357  } {
   358    {UPDATE t1 0 X.. {i 1 {} {} t I} {{} {} {} {} t o}}
   359  }
   360  do_iterator_test 6.1.4 * {
   361    SELECT indirect(0);
   362    UPDATE t1 SET c = 'x' WHERE a = 1;
   363    SELECT indirect(1);
   364    UPDATE t1 SET c = 'i' WHERE a = 1;
   365  } {
   366    {UPDATE t1 0 X.. {i 1 {} {} t o} {{} {} {} {} t i}}
   367  }
   368  do_iterator_test 6.1.4 * {
   369    SELECT indirect(1);
   370    UPDATE t1 SET c = 'y' WHERE a = 1;
   371    SELECT indirect(1);
   372    UPDATE t1 SET c = 'I' WHERE a = 1;
   373  } {
   374    {UPDATE t1 1 X.. {i 1 {} {} t i} {{} {} {} {} t I}}
   375  }
   376  
   377  do_iterator_test 6.1.5 * {
   378    INSERT INTO t2 VALUES(1, 'x');
   379  } {
   380    {INSERT t2 0 X. {} {i 1 t x}}
   381    {INSERT t2 1 X. {} {i 2 n {}}}
   382  }
   383  
   384  do_iterator_test 6.1.6 * {
   385    SELECT indirect(1);
   386    INSERT INTO t2 VALUES(3, 'x');
   387    SELECT indirect(0);
   388    UPDATE t2 SET y = 'y' WHERE x>2;
   389  } {
   390    {INSERT t2 0 X. {} {i 3 t y}}
   391    {INSERT t2 0 X. {} {i 4 t y}}
   392  }
   393  
   394  do_iterator_test 6.1.7 * {
   395    SELECT indirect(1);
   396    DELETE FROM t2 WHERE x = 4;
   397    SELECT indirect(0);
   398    INSERT INTO t2 VALUES(4, 'new');
   399  } {
   400    {UPDATE t2 0 X. {i 4 t y} {{} {} t new}}
   401  }
   402  
   403  do_iterator_test 6.1.8 * {
   404    CREATE TABLE t3(a, b PRIMARY KEY);
   405    CREATE TABLE t4(a, b PRIMARY KEY);
   406    CREATE TRIGGER t4t AFTER UPDATE ON t4 BEGIN
   407      UPDATE t3 SET a = new.a WHERE b = new.b;
   408    END;
   409  
   410    SELECT indirect(1);
   411    INSERT INTO t3 VALUES('one', 1);
   412    INSERT INTO t4 VALUES('one', 1);
   413    SELECT indirect(0);
   414    UPDATE t4 SET a = 'two' WHERE b = 1;
   415  } {
   416    {INSERT t3 1 .X {} {t two i 1}}
   417    {INSERT t4 0 .X {} {t two i 1}} 
   418  }
   419  
   420  sqlite3session S db main
   421  do_execsql_test 6.2.1 {
   422    SELECT indirect(0);
   423    SELECT indirect(-1);
   424    SELECT indirect(45);
   425    SELECT indirect(-100);
   426  } {0 0 1 1}
   427  S delete
   428  
   429  #-------------------------------------------------------------------------
   430  # Test that if a conflict-handler that has been passed either NOTFOUND or
   431  # CONSTRAINT returns REPLACE - the sqlite3changeset_apply() call returns
   432  # MISUSE and rolls back any changes made so far.
   433  #
   434  #   7.1.*: NOTFOUND conflict-callback.
   435  #   7.2.*: CONSTRAINT conflict-callback.
   436  #
   437  proc xConflict {args} {return REPLACE}
   438  test_reset
   439  
   440  do_execsql_test 7.1.1 {
   441    CREATE TABLE t1(a PRIMARY KEY, b);
   442    INSERT INTO t1 VALUES(1, 'one');
   443    INSERT INTO t1 VALUES(2, 'two');
   444  }
   445  do_test 7.1.2 {
   446    execsql {
   447      CREATE TABLE t1(a PRIMARY KEY, b NOT NULL);
   448      INSERT INTO t1 VALUES(1, 'one');
   449    } db2
   450  } {}
   451  do_test 7.1.3 {
   452    set changeset [changeset_from_sql {
   453      UPDATE t1 SET b = 'five' WHERE a = 1;
   454      UPDATE t1 SET b = 'six' WHERE a = 2;
   455    }]
   456    set x [list]
   457    sqlite3session_foreach c $changeset { lappend x $c }
   458    set x
   459  } [list \
   460    {UPDATE t1 0 X. {i 1 t one} {{} {} t five}} \
   461    {UPDATE t1 0 X. {i 2 t two} {{} {} t six}}  \
   462  ]
   463  do_test 7.1.4 {
   464    list [catch {sqlite3changeset_apply db2 $changeset xConflict} msg] $msg
   465  } {1 SQLITE_MISUSE}
   466  do_test 7.1.5 { execsql { SELECT * FROM t1 } db2 } {1 one}
   467  
   468  do_test 7.2.1 {
   469    set changeset [changeset_from_sql { UPDATE t1 SET b = NULL WHERE a = 1 }]
   470  
   471    set x [list]
   472    sqlite3session_foreach c $changeset { lappend x $c }
   473    set x
   474  } [list \
   475    {UPDATE t1 0 X. {i 1 t five} {{} {} n {}}} \
   476  ]
   477  do_test 7.2.2 {
   478    list [catch {sqlite3changeset_apply db2 $changeset xConflict} msg] $msg
   479  } {1 SQLITE_MISUSE}
   480  do_test 7.2.3 { execsql { SELECT * FROM t1 } db2 } {1 one}
   481  
   482  #-------------------------------------------------------------------------
   483  # Test that if a conflict-handler returns ABORT, application of the 
   484  # changeset is rolled back and the sqlite3changeset_apply() method returns
   485  # SQLITE_ABORT.
   486  #
   487  # Also test that the same thing happens if a conflict handler returns an
   488  # unrecognized integer value. Except, in this case SQLITE_MISUSE is returned
   489  # instead of SQLITE_ABORT.
   490  #
   491  foreach {tn conflict_return apply_return} {
   492    1    ABORT   SQLITE_ABORT
   493    2    567     SQLITE_MISUSE
   494  } {
   495    test_reset
   496    proc xConflict {args} [list return $conflict_return]
   497  
   498    do_test 8.$tn.0 {
   499      do_common_sql { 
   500        CREATE TABLE t1(x, y, PRIMARY KEY(x, y));
   501        INSERT INTO t1 VALUES('x', 'y');
   502      }
   503      execsql { INSERT INTO t1 VALUES('w', 'w') }
   504  
   505      set changeset [changeset_from_sql { DELETE FROM t1 WHERE 1 }]
   506  
   507      set x [list]
   508      sqlite3session_foreach c $changeset { lappend x $c }
   509      set x
   510    } [list \
   511      {DELETE t1 0 XX {t w t w} {}} \
   512      {DELETE t1 0 XX {t x t y} {}} \
   513    ]
   514  
   515    do_test 8.$tn.1 {
   516      list [catch {sqlite3changeset_apply db2 $changeset xConflict} msg] $msg
   517    } [list 1 $apply_return]
   518  
   519    do_test 8.$tn.2 {
   520      execsql {SELECT * FROM t1} db2
   521    } {x y}
   522  }
   523  
   524  
   525  #-------------------------------------------------------------------------
   526  # Try to cause an infinite loop as follows:
   527  #
   528  #   1. Have a changeset insert a row that causes a CONFLICT callback,
   529  #   2. Have the conflict handler return REPLACE,
   530  #   3. After the session module deletes the conflicting row, have a trigger
   531  #      re-insert it.
   532  #   4. Goto step 1...
   533  #
   534  # This doesn't work, as the second invocation of the conflict handler is a
   535  # CONSTRAINT, not a CONFLICT. There is at most one CONFLICT callback for
   536  # each change in the changeset.
   537  #
   538  test_reset
   539  proc xConflict {type args} { 
   540    if {$type == "CONFLICT"} { return REPLACE }
   541    return OMIT
   542  }
   543  do_test 9.1 {
   544    execsql {
   545      CREATE TABLE t1(a PRIMARY KEY, b);
   546    }
   547    execsql {
   548      CREATE TABLE t1(a PRIMARY KEY, b);
   549      INSERT INTO t1 VALUES('x', 2);
   550      CREATE TRIGGER tr1 AFTER DELETE ON t1 BEGIN
   551        INSERT INTO t1 VALUES(old.a, old.b);
   552      END;
   553    } db2
   554  } {}
   555  do_test 9.2 {
   556    set changeset [changeset_from_sql { INSERT INTO t1 VALUES('x', 1) }]
   557    sqlite3changeset_apply db2 $changeset xConflict
   558  } {}
   559  do_test 9.3 {
   560    execsql { SELECT * FROM t1 } db2
   561  } {x 2}
   562  
   563  #-------------------------------------------------------------------------
   564  #
   565  test_reset
   566  db function enable [list S enable]
   567  
   568  do_common_sql {
   569    CREATE TABLE t1(a PRIMARY KEY, b);
   570    INSERT INTO t1 VALUES('x', 'X');
   571  }
   572  
   573  do_iterator_test 10.1 t1 {
   574    INSERT INTO t1 VALUES('y', 'Y');
   575    SELECT enable(0);
   576    INSERT INTO t1 VALUES('z', 'Z');
   577    SELECT enable(1);
   578  } {
   579    {INSERT t1 0 X. {} {t y t Y}}
   580  }
   581  
   582  sqlite3session S db main
   583  do_execsql_test 10.2 {
   584    SELECT enable(0);
   585    SELECT enable(-1);
   586    SELECT enable(1);
   587    SELECT enable(-1);
   588  } {0 0 1 1}
   589  S delete
   590  
   591  finish_test