/ Check-in [856f8604]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Experimental change to invoke the preupdate hook when WITHOUT ROWID tables are written.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | preupdate-without-rowid
Files: files | file ages | folders
SHA1: 856f8604c59c8fdd9bfb7d86fc0e212f091ab49a
User & Date: dan 2017-01-30 19:44:53
Context
2017-01-31
14:08
Merge latest trunk with this branch. check-in: 4a592abb user: dan tags: preupdate-without-rowid
2017-01-30
19:44
Experimental change to invoke the preupdate hook when WITHOUT ROWID tables are written. check-in: 856f8604 user: dan tags: preupdate-without-rowid
11:38
Fix building with SQLITE_OMIT_FOREIGN_KEY defined. check-in: e93d2c49 user: dan tags: trunk
Changes
Hide Diffs Side-by-Side Diffs Ignore Whitespace Patch

Changes to ext/session/session1.test.

    16     16   } 
    17     17   source [file join [file dirname [info script]] session_common.tcl]
    18     18   source $testdir/tester.tcl
    19     19   ifcapable !session {finish_test; return}
    20     20   
    21     21   set testprefix session1
    22     22   
    23         -do_execsql_test 1.0 {
    24         -  CREATE TABLE t1(x PRIMARY KEY, y);
           23  +# Run all tests in this file twice. Once with "WITHOUT ROWID", and once
           24  +# with regular rowid tables.
           25  +#
           26  +foreach {tn trailing} {
           27  +  1 ""
           28  +  2 " WITHOUT ROWID "
           29  +} {
           30  +eval [string map [list %WR% $trailing] {
           31  +
           32  +db close
           33  +forcedelete test.db test.db2
           34  +reset_db
           35  +
           36  +do_execsql_test $tn.1.0 {
           37  +  CREATE TABLE t1(x PRIMARY KEY, y) %WR%;
    25     38     INSERT INTO t1 VALUES('abc', 'def');
    26     39   }
    27     40   
    28     41   #-------------------------------------------------------------------------
    29     42   # Test creating, attaching tables to and deleting session objects.
    30     43   #
    31         -do_test 1.1 { sqlite3session S db main } {S}
    32         -do_test 1.2 { S delete } {}
    33         -do_test 1.3 { sqlite3session S db main } {S}
    34         -do_test 1.4 { S attach t1 } {}
    35         -do_test 1.5 { S delete } {}
    36         -do_test 1.6 { sqlite3session S db main } {S}
    37         -do_test 1.7 { S attach t1 ; S attach t2 ; S attach t3 } {}
    38         -do_test 1.8 { S attach t1 ; S attach t2 ; S attach t3 } {}
    39         -do_test 1.9 { S delete } {}
    40         -do_test 1.10 {
           44  +do_test $tn.1.1 { sqlite3session S db main } {S}
           45  +do_test $tn.1.2 { S delete } {}
           46  +do_test $tn.1.3 { sqlite3session S db main } {S}
           47  +do_test $tn.1.4 { S attach t1 } {}
           48  +do_test $tn.1.5 { S delete } {}
           49  +do_test $tn.1.6 { sqlite3session S db main } {S}
           50  +do_test $tn.1.7 { S attach t1 ; S attach t2 ; S attach t3 } {}
           51  +do_test $tn.1.8 { S attach t1 ; S attach t2 ; S attach t3 } {}
           52  +do_test $tn.1.9 { S delete } {}
           53  +do_test $tn.1.10 {
    41     54     sqlite3session S db main
    42     55     S attach t1
    43     56     execsql { INSERT INTO t1 VALUES('ghi', 'jkl') }
    44     57   } {}
    45         -do_test 1.11 { S delete } {}
    46         -do_test 1.12 {
    47         -  sqlite3session S db main
    48         -  S attach t1
    49         -  execsql { INSERT INTO t1 VALUES('mno', 'pqr') }
    50         -  execsql { UPDATE t1 SET x = 111 WHERE rowid = 1 }
    51         -  execsql { DELETE FROM t1 WHERE rowid = 2 }
    52         -} {}
    53         -do_test 1.13 {
    54         -  S changeset
    55         -  S delete
    56         -} {}
           58  +do_test $tn.1.11 { S delete } {}
           59  +if {$tn==1} {
           60  +  do_test $tn.1.12 {
           61  +    sqlite3session S db main
           62  +    S attach t1
           63  +    execsql { INSERT INTO t1 VALUES('mno', 'pqr') }
           64  +    execsql { UPDATE t1 SET x = 111 WHERE rowid = 1 }
           65  +    execsql { DELETE FROM t1 WHERE rowid = 2 }
           66  +  } {}
           67  +  do_test $tn.1.13 {
           68  +    S changeset
           69  +    S delete
           70  +  } {}
           71  +}
    57     72   
    58     73   #-------------------------------------------------------------------------
    59     74   # Simple changeset tests. Also test the sqlite3changeset_invert() 
    60     75   # function.
    61     76   #
    62         -do_test 2.1.1 {
           77  +do_test $tn.2.1.1 {
    63     78     execsql { DELETE FROM t1 }
    64     79     sqlite3session S db main
    65     80     S attach t1
    66     81     execsql { INSERT INTO t1 VALUES(1, 'Sukhothai') }
    67     82     execsql { INSERT INTO t1 VALUES(2, 'Ayutthaya') }
    68     83     execsql { INSERT INTO t1 VALUES(3, 'Thonburi') }
    69     84   } {}
    70         -do_changeset_test 2.1.2 S {
           85  +do_changeset_test $tn.2.1.2 S {
    71     86     {INSERT t1 0 X. {} {i 1 t Sukhothai}}
    72     87     {INSERT t1 0 X. {} {i 2 t Ayutthaya}}
    73     88     {INSERT t1 0 X. {} {i 3 t Thonburi}}
    74     89   }
    75         -do_changeset_invert_test 2.1.3 S {
           90  +do_changeset_invert_test $tn.2.1.3 S {
    76     91     {DELETE t1 0 X. {i 1 t Sukhothai} {}}
    77     92     {DELETE t1 0 X. {i 2 t Ayutthaya} {}}
    78     93     {DELETE t1 0 X. {i 3 t Thonburi} {}}
    79     94   }
    80         -do_test 2.1.4 { S delete } {}
           95  +do_test $tn.2.1.4 { S delete } {}
    81     96   
    82         -do_test 2.2.1 {
           97  +do_test $tn.2.2.1 {
    83     98     sqlite3session S db main
    84     99     S attach t1
    85    100     execsql { DELETE FROM t1 WHERE 1 }
    86    101   } {}
    87         -do_changeset_test 2.2.2 S {
          102  +do_changeset_test $tn.2.2.2 S {
    88    103     {DELETE t1 0 X. {i 1 t Sukhothai} {}}
    89    104     {DELETE t1 0 X. {i 2 t Ayutthaya} {}}
    90    105     {DELETE t1 0 X. {i 3 t Thonburi} {}}
    91    106   }
    92         -do_changeset_invert_test 2.2.3 S {
          107  +do_changeset_invert_test $tn.2.2.3 S {
    93    108     {INSERT t1 0 X. {} {i 1 t Sukhothai}}
    94    109     {INSERT t1 0 X. {} {i 2 t Ayutthaya}}
    95    110     {INSERT t1 0 X. {} {i 3 t Thonburi}}
    96    111   }
    97         -do_test 2.2.4 { S delete } {}
          112  +do_test $tn.2.2.4 { S delete } {}
    98    113   
    99         -do_test 2.3.1 {
          114  +do_test $tn.2.3.1 {
   100    115     execsql { DELETE FROM t1 }
   101    116     sqlite3session S db main
   102    117     execsql { INSERT INTO t1 VALUES(1, 'Sukhothai') }
   103    118     execsql { INSERT INTO t1 VALUES(2, 'Ayutthaya') }
   104    119     execsql { INSERT INTO t1 VALUES(3, 'Thonburi') }
   105    120     S attach t1
   106    121     execsql { 
   107    122       UPDATE t1 SET x = 10 WHERE x = 1;
   108    123       UPDATE t1 SET y = 'Surin' WHERE x = 2;
   109    124       UPDATE t1 SET x = 20, y = 'Thapae' WHERE x = 3;
   110    125     }
   111    126   } {}
   112    127   
   113         -do_changeset_test 2.3.2 S {
          128  +do_changeset_test $tn.2.3.2 S {
   114    129     {INSERT t1 0 X. {} {i 10 t Sukhothai}} 
   115    130     {DELETE t1 0 X. {i 1 t Sukhothai} {}} 
   116    131     {UPDATE t1 0 X. {i 2 t Ayutthaya} {{} {} t Surin}} 
   117    132     {DELETE t1 0 X. {i 3 t Thonburi} {}} 
   118    133     {INSERT t1 0 X. {} {i 20 t Thapae}} 
   119    134   }
   120    135   
   121         -do_changeset_invert_test 2.3.3 S {
          136  +do_changeset_invert_test $tn.2.3.3 S {
   122    137     {DELETE t1 0 X. {i 10 t Sukhothai} {}} 
   123    138     {INSERT t1 0 X. {} {i 1 t Sukhothai}} 
   124    139     {UPDATE t1 0 X. {i 2 t Surin} {{} {} t Ayutthaya}} 
   125    140     {INSERT t1 0 X. {} {i 3 t Thonburi}} 
   126    141     {DELETE t1 0 X. {i 20 t Thapae} {}}
   127    142   }
   128         -do_test 2.3.4 { S delete } {}
          143  +do_test $tn.2.3.4 { S delete } {}
   129    144   
   130         -do_test 2.4.1 {
          145  +do_test $tn.2.4.1 {
   131    146     sqlite3session S db main
   132    147     S attach t1
   133    148     execsql { INSERT INTO t1 VALUES(100, 'Bangkok') }
   134    149     execsql { DELETE FROM t1 WHERE x = 100 }
   135    150   } {}
   136         -do_changeset_test 2.4.2 S {}
   137         -do_changeset_invert_test 2.4.3 S {}
   138         -do_test 2.4.4 { S delete } {}
          151  +do_changeset_test $tn.2.4.2 S {}
          152  +do_changeset_invert_test $tn.2.4.3 S {}
          153  +do_test $tn.2.4.4 { S delete } {}
   139    154   
   140    155   #-------------------------------------------------------------------------
   141    156   # Test the application of simple changesets. These tests also test that
   142    157   # the conflict callback is invoked correctly. For these tests, the 
   143    158   # conflict callback always returns OMIT.
   144    159   #
   145    160   db close
................................................................................
   185    200   
   186    201   proc do_db2_test {testname sql {result {}}} {
   187    202     uplevel do_test $testname [list "execsql {$sql} db2"] [list [list {*}$result]]
   188    203   }
   189    204   
   190    205   # Test INSERT changesets.
   191    206   #
   192         -do_test 3.1.0 {
   193         -  execsql { CREATE TABLE t1(a PRIMARY KEY, b NOT NULL) } db2
          207  +do_test $tn.3.1.0 {
          208  +  execsql { CREATE TABLE t1(a PRIMARY KEY, b NOT NULL) %WR% } db2
   194    209     execsql { 
   195         -    CREATE TABLE t1(a PRIMARY KEY, b);
          210  +    CREATE TABLE t1(a PRIMARY KEY, b) %WR%;
   196    211       INSERT INTO t1 VALUES(1, 'one');
   197    212       INSERT INTO t1 VALUES(2, 'two');
   198    213     } db 
   199    214   } {}
   200         -do_db2_test 3.1.1 "INSERT INTO t1 VALUES(6, 'VI')"
   201         -do_conflict_test 3.1.2 -tables t1 -sql {
          215  +do_db2_test $tn.3.1.1 "INSERT INTO t1 VALUES(6, 'VI')"
          216  +do_conflict_test $tn.3.1.2 -tables t1 -sql {
   202    217     INSERT INTO t1 VALUES(3, 'three');
   203    218     INSERT INTO t1 VALUES(4, 'four');
   204    219     INSERT INTO t1 VALUES(5, 'five');
   205    220     INSERT INTO t1 VALUES(6, 'six');
   206    221     INSERT INTO t1 VALUES(7, 'seven');
   207    222     INSERT INTO t1 VALUES(8, NULL);
   208    223   } -conflicts {
   209    224     {INSERT t1 CONFLICT {i 6 t six} {i 6 t VI}}
   210    225     {INSERT t1 CONSTRAINT {i 8 n {}}}
   211    226   }
   212    227   
   213         -do_db2_test 3.1.3 "SELECT * FROM t1" {
   214         -  6 VI 3 three 4 four 5 five 7 seven
          228  +do_db2_test $tn.3.1.3 "SELECT * FROM t1 ORDER BY a" {
          229  +  3 three 4 four 5 five 6 VI 7 seven
   215    230   }
   216         -do_execsql_test 3.1.4 "SELECT * FROM t1" {
          231  +do_execsql_test $tn.3.1.4 "SELECT * FROM t1" {
   217    232     1 one 2 two 3 three 4 four 5 five 6 six 7 seven 8 {}
   218    233   }
   219    234   
   220    235   # Test DELETE changesets.
   221    236   #
   222         -do_execsql_test 3.2.1 {
          237  +do_execsql_test $tn.3.2.1 {
   223    238     PRAGMA foreign_keys = on;
   224         -  CREATE TABLE t2(a PRIMARY KEY, b);
          239  +  CREATE TABLE t2(a PRIMARY KEY, b)%WR%;
   225    240     CREATE TABLE t3(c, d REFERENCES t2);
   226    241     INSERT INTO t2 VALUES(1, 'one');
   227    242     INSERT INTO t2 VALUES(2, 'two');
   228    243     INSERT INTO t2 VALUES(3, 'three');
   229    244     INSERT INTO t2 VALUES(4, 'four');
   230    245   }
   231         -do_db2_test 3.2.2 {
          246  +do_db2_test $tn.3.2.2 {
   232    247     PRAGMA foreign_keys = on;
   233         -  CREATE TABLE t2(a PRIMARY KEY, b);
          248  +  CREATE TABLE t2(a PRIMARY KEY, b)%WR%;
   234    249     CREATE TABLE t3(c, d REFERENCES t2);
   235    250     INSERT INTO t2 VALUES(1, 'one');
   236    251     INSERT INTO t2 VALUES(2, 'two');
   237    252     INSERT INTO t2 VALUES(4, 'five');
   238    253     INSERT INTO t3 VALUES('i', 1);
   239    254   }
   240         -do_conflict_test 3.2.3 -tables t2 -sql {
          255  +do_conflict_test $tn.3.2.3 -tables t2 -sql {
   241    256     DELETE FROM t2 WHERE a = 1;
   242    257     DELETE FROM t2 WHERE a = 2;
   243    258     DELETE FROM t2 WHERE a = 3;
   244    259     DELETE FROM t2 WHERE a = 4;
   245    260   } -conflicts {
   246    261     {DELETE t2 NOTFOUND {i 3 t three}}
   247    262     {DELETE t2 DATA {i 4 t four} {i 4 t five}}
   248    263     {FOREIGN_KEY 1}
   249    264   }
   250         -do_execsql_test 3.2.4 "SELECT * FROM t2" {}
   251         -do_db2_test     3.2.5 "SELECT * FROM t2" {4 five}
          265  +do_execsql_test $tn.3.2.4 "SELECT * FROM t2" {}
          266  +do_db2_test $tn.3.2.5 "SELECT * FROM t2" {4 five}
   252    267   
   253    268   # Test UPDATE changesets.
   254    269   #
   255         -do_execsql_test 3.3.1 {
   256         -  CREATE TABLE t4(a, b, c, PRIMARY KEY(b, c));
          270  +do_execsql_test $tn.3.3.1 {
          271  +  CREATE TABLE t4(a, b, c, PRIMARY KEY(b, c))%WR%;
   257    272     INSERT INTO t4 VALUES(1, 2, 3);
   258    273     INSERT INTO t4 VALUES(4, 5, 6);
   259    274     INSERT INTO t4 VALUES(7, 8, 9);
   260    275     INSERT INTO t4 VALUES(10, 11, 12);
   261    276   }
   262         -do_db2_test 3.3.2 {
   263         -  CREATE TABLE t4(a NOT NULL, b, c, PRIMARY KEY(b, c));
          277  +do_db2_test $tn.3.3.2 {
          278  +  CREATE TABLE t4(a NOT NULL, b, c, PRIMARY KEY(b, c))%WR%;
   264    279     INSERT INTO t4 VALUES(0, 2, 3);
   265    280     INSERT INTO t4 VALUES(4, 5, 7);
   266    281     INSERT INTO t4 VALUES(7, 8, 9);
   267    282     INSERT INTO t4 VALUES(10, 11, 12);
   268    283   }
   269         -do_conflict_test 3.3.3 -tables t4 -sql {
          284  +do_conflict_test $tn.3.3.3 -tables t4 -sql {
   270    285     UPDATE t4 SET a = -1 WHERE b = 2;
   271    286     UPDATE t4 SET a = -1 WHERE b = 5;
   272    287     UPDATE t4 SET a = NULL WHERE c = 9;
   273    288     UPDATE t4 SET a = 'x' WHERE b = 11;
   274    289   } -conflicts {
   275    290     {UPDATE t4 DATA {i 1 i 2 i 3} {i -1 {} {} {} {}} {i 0 i 2 i 3}}
   276    291     {UPDATE t4 NOTFOUND {i 4 i 5 i 6} {i -1 {} {} {} {}}}
   277    292     {UPDATE t4 CONSTRAINT {i 7 i 8 i 9} {n {} {} {} {} {}}}
   278    293   }
   279         -do_db2_test     3.3.4 { SELECT * FROM t4 } {0 2 3 4 5 7 7 8 9 x 11 12}
   280         -do_execsql_test 3.3.5 { SELECT * FROM t4 } {-1 2 3 -1 5 6 {} 8 9 x 11 12}
          294  +do_db2_test $tn.3.3.4 { SELECT * FROM t4 } {0 2 3 4 5 7 7 8 9 x 11 12}
          295  +do_execsql_test $tn.3.3.5 { SELECT * FROM t4 } {-1 2 3 -1 5 6 {} 8 9 x 11 12}
   281    296   
   282    297   #-------------------------------------------------------------------------
   283    298   # This next block of tests verifies that values returned by the conflict
   284    299   # handler are intepreted correctly.
   285    300   #
   286    301   
   287    302   proc test_reset {} {
................................................................................
   293    308   }
   294    309   
   295    310   proc xConflict {args} {
   296    311     lappend ::xConflict $args
   297    312     return $::conflict_return
   298    313   }
   299    314   
   300         -foreach {tn conflict_return after} {
          315  +foreach {tn2 conflict_return after} {
   301    316     1 OMIT      {1 2 value1   4 5 7       10 x x}
   302    317     2 REPLACE   {1 2 value1   4 5 value2  10 8 9}
   303    318   } {
   304    319     test_reset
   305    320   
   306         -  do_test 4.$tn.1 {
          321  +  do_test $tn.4.$tn2.1 {
   307    322       foreach db {db db2} {
   308    323         execsql { 
   309         -        CREATE TABLE t1(a, b, c, PRIMARY KEY(a));
          324  +        CREATE TABLE t1(a, b, c, PRIMARY KEY(a))%WR%;
   310    325           INSERT INTO t1 VALUES(1, 2, 3);
   311    326           INSERT INTO t1 VALUES(4, 5, 6);
   312    327           INSERT INTO t1 VALUES(7, 8, 9);
   313    328         } $db
   314    329       }
   315    330       execsql { 
   316    331         REPLACE INTO t1 VALUES(4, 5, 7);
   317    332         REPLACE INTO t1 VALUES(10, 'x', 'x');
   318    333       } db2
   319    334     } {}
   320    335   
   321         -  do_conflict_test 4.$tn.2 -tables t1 -sql {
          336  +  do_conflict_test $tn.4.$tn2.2 -tables t1 -sql {
   322    337       UPDATE t1 SET c = 'value1' WHERE a = 1;       -- no conflict
   323    338       UPDATE t1 SET c = 'value2' WHERE a = 4;       -- DATA conflict
   324    339       UPDATE t1 SET a = 10 WHERE a = 7;             -- CONFLICT conflict
   325    340     } -conflicts {
   326    341       {INSERT t1 CONFLICT {i 10 i 8 i 9} {i 10 t x t x}}
   327    342       {UPDATE t1 DATA {i 4 {} {} i 6} {{} {} {} {} t value2} {i 4 i 5 i 7}}
   328    343     }
   329    344   
   330         -  do_db2_test 4.$tn.3 "SELECT * FROM t1 ORDER BY a" $after
          345  +  do_db2_test $tn.4.$tn2.3 "SELECT * FROM t1 ORDER BY a" $after
   331    346   }
   332    347   
   333         -foreach {tn conflict_return} {
          348  +foreach {tn2 conflict_return} {
   334    349     1 OMIT
   335    350     2 REPLACE
   336    351   } {
   337    352     test_reset
   338    353   
   339         -  do_test 5.$tn.1 {
          354  +  do_test $tn.5.$tn2.1 {
   340    355       # Create an identical schema in both databases.
   341    356       set schema {
   342         -      CREATE TABLE "'foolish name'"(x, y, z, PRIMARY KEY(x, y));
          357  +      CREATE TABLE "'foolish name'"(x, y, z, PRIMARY KEY(x, y))%WR%;
   343    358       }
   344    359       execsql $schema db
   345    360       execsql $schema db2
   346    361   
   347    362       # Add some rows to [db2]. These rows will cause conflicts later
   348    363       # on when the changeset from [db] is applied to it.
   349    364       execsql { 
................................................................................
   350    365         INSERT INTO "'foolish name'" VALUES('one', 'one', 'ii');
   351    366         INSERT INTO "'foolish name'" VALUES('one', 'two', 'i');
   352    367         INSERT INTO "'foolish name'" VALUES('two', 'two', 'ii');
   353    368       } db2
   354    369   
   355    370     } {}
   356    371   
   357         -  do_conflict_test 5.$tn.2 -tables {{'foolish name'}} -sql {
          372  +  do_conflict_test $tn.5.$tn2.2 -tables {{'foolish name'}} -sql {
   358    373       INSERT INTO "'foolish name'" VALUES('one', 'two', 2);
   359    374     } -conflicts {
   360    375       {INSERT {'foolish name'} CONFLICT {t one t two i 2} {t one t two t i}}
   361    376     }
   362    377   
   363    378     set res(REPLACE) {one one ii one two 2 two two ii}
   364    379     set res(OMIT)    {one one ii one two i two two ii}
   365         -  do_db2_test 5.$tn.3 {
          380  +  do_db2_test $tn.5.$tn2.3 {
   366    381       SELECT * FROM "'foolish name'" ORDER BY x, y
   367    382     } $res($conflict_return)
   368    383   
   369    384   
   370         -  do_test 5.$tn.1 {
          385  +  do_test $tn.5.$tn2.1 {
   371    386       set schema {
   372         -      CREATE TABLE d1("z""z" PRIMARY KEY, y);
          387  +      CREATE TABLE d1("z""z" PRIMARY KEY, y)%WR%;
   373    388         INSERT INTO d1 VALUES(1, 'one');
   374    389         INSERT INTO d1 VALUES(2, 'two');
   375    390       }
   376    391       execsql $schema db
   377    392       execsql $schema db2
   378    393   
   379    394       execsql { 
   380    395         UPDATE d1 SET y = 'TWO' WHERE "z""z" = 2;
   381    396       } db2
   382    397   
   383    398     } {}
   384    399   
   385         -  do_conflict_test 5.$tn.2 -tables d1 -sql {
          400  +  do_conflict_test $tn.5.$tn2.2 -tables d1 -sql {
   386    401       DELETE FROM d1 WHERE "z""z" = 2;
   387    402     } -conflicts {
   388    403       {DELETE d1 DATA {i 2 t two} {i 2 t TWO}}
   389    404     }
   390    405   
   391    406     set res(REPLACE) {1 one}
   392    407     set res(OMIT)    {1 one 2 TWO}
   393         -  do_db2_test 5.$tn.3 "SELECT * FROM d1" $res($conflict_return)
          408  +  do_db2_test $tn.5.$tn2.3 "SELECT * FROM d1" $res($conflict_return)
   394    409   }
   395    410   
   396    411   #-------------------------------------------------------------------------
   397    412   # Test that two tables can be monitored by a single session object.
   398    413   #
   399    414   test_reset
   400    415   set schema {
   401         -  CREATE TABLE t1(a COLLATE nocase PRIMARY KEY, b);
   402         -  CREATE TABLE t2(a, b PRIMARY KEY);
          416  +  CREATE TABLE t1(a COLLATE nocase PRIMARY KEY, b)%WR%;
          417  +  CREATE TABLE t2(a, b PRIMARY KEY)%WR%;
   403    418   }
   404         -do_test 6.0 {
          419  +do_test $tn.6.0 {
   405    420     execsql $schema db
   406    421     execsql $schema db2
   407    422     execsql {
   408    423       INSERT INTO t1 VALUES('a', 'b');
   409    424       INSERT INTO t2 VALUES('a', 'b');
   410    425     } db2
   411    426   } {}
   412    427   
   413    428   set conflict_return ""
   414         -do_conflict_test 6.1 -tables {t1 t2} -sql {
          429  +do_conflict_test $tn.6.1 -tables {t1 t2} -sql {
   415    430     INSERT INTO t1 VALUES('1', '2');
   416    431     INSERT INTO t1 VALUES('A', 'B');
   417    432     INSERT INTO t2 VALUES('A', 'B');
   418    433   } -conflicts {
   419    434     {INSERT t1 CONFLICT {t A t B} {t a t b}}
   420    435   }
   421    436   
   422         -do_db2_test 6.2 "SELECT * FROM t1" {a b 1 2}
   423         -do_db2_test 6.3 "SELECT * FROM t2" {a b A B}
          437  +do_db2_test $tn.6.2 "SELECT * FROM t1 ORDER BY a" {1 2 a b}
          438  +do_db2_test $tn.6.3 "SELECT * FROM t2 ORDER BY a" {A B a b}
   424    439   
   425    440   #-------------------------------------------------------------------------
   426    441   # Test that session objects are not confused by changes to table in
   427    442   # other databases.
   428    443   #
   429    444   catch { db2 close }
   430    445   drop_all_tables
   431    446   forcedelete test.db2
   432         -do_iterator_test 7.1 * {
          447  +do_iterator_test $tn.7.1 * {
   433    448     ATTACH 'test.db2' AS aux;
   434         -  CREATE TABLE main.t1(x PRIMARY KEY, y);
   435         -  CREATE TABLE aux.t1(x PRIMARY KEY, y);
          449  +  CREATE TABLE main.t1(x PRIMARY KEY, y)%WR%;
          450  +  CREATE TABLE aux.t1(x PRIMARY KEY, y)%WR%;
   436    451   
   437    452     INSERT INTO main.t1 VALUES('one', 1);
   438    453     INSERT INTO main.t1 VALUES('two', 2);
   439    454     INSERT INTO aux.t1 VALUES('three', 3);
   440    455     INSERT INTO aux.t1 VALUES('four', 4);
   441    456   } {
   442    457     {INSERT t1 0 X. {} {t two i 2}} 
   443    458     {INSERT t1 0 X. {} {t one i 1}}
   444    459   }
   445    460   
   446    461   #-------------------------------------------------------------------------
   447    462   # Test the sqlite3session_isempty() function.
   448    463   #
   449         -do_test 8.1 {
          464  +do_test $tn.8.1 {
   450    465     execsql {
   451         -    CREATE TABLE t5(x PRIMARY KEY, y);
   452         -    CREATE TABLE t6(x PRIMARY KEY, y);
          466  +    CREATE TABLE t5(x PRIMARY KEY, y)%WR%;
          467  +    CREATE TABLE t6(x PRIMARY KEY, y)%WR%;
   453    468       INSERT INTO t5 VALUES('a', 'b');
   454    469       INSERT INTO t6 VALUES('a', 'b');
   455    470     }
   456    471     sqlite3session S db main
   457    472     S attach *
   458    473   
   459    474     S isempty
   460    475   } {1}
   461         -do_test 8.2 {
          476  +do_test $tn.8.2 {
   462    477     execsql { DELETE FROM t5 }
   463    478     S isempty
   464    479   } {0}
   465         -do_test 8.3 {
          480  +do_test $tn.8.3 {
   466    481     S delete
   467    482     sqlite3session S db main
   468    483     S attach t5
   469    484     execsql { DELETE FROM t5 }
   470    485     S isempty
   471    486   } {1}
   472         -do_test 8.4 { S delete } {}
          487  +do_test $tn.8.4 { S delete } {}
   473    488   
   474         -do_test 8.5 {
          489  +do_test $tn.8.5 {
   475    490     sqlite3session S db main
   476    491     S attach t5
   477    492     S attach t6
   478    493     execsql { INSERT INTO t5 VALUES(1, 2) }
   479    494     S isempty
   480    495   } {0}
   481    496   
   482         -do_test 8.6 {
          497  +do_test $tn.8.6 {
   483    498     S delete
   484    499     sqlite3session S db main
   485    500     S attach t5
   486    501     S attach t6
   487    502     execsql { INSERT INTO t6 VALUES(1, 2) }
   488    503     S isempty
   489    504   } {0}
   490         -do_test 8.7 { S delete } {}
          505  +do_test $tn.8.7 { S delete } {}
   491    506   
   492    507   #-------------------------------------------------------------------------
   493    508   #
   494         -do_execsql_test 9.1 {
   495         -  CREATE TABLE t7(a, b, c, d, e PRIMARY KEY, f, g);
          509  +do_execsql_test $tn.9.1 {
          510  +  CREATE TABLE t7(a, b, c, d, e PRIMARY KEY, f, g)%WR%;
   496    511     INSERT INTO t7 VALUES(1, 1, 1, 1, 1, 1, 1);
   497    512   }
   498         -do_test 9.2 { 
          513  +do_test $tn.9.2 { 
   499    514     sqlite3session S db main 
   500    515     S attach *
   501    516     execsql { UPDATE t7 SET b=2, d=2 }
   502    517   } {}
   503         -do_changeset_test 9.2 S {{UPDATE t7 0 ....X.. {{} {} i 1 {} {} i 1 i 1 {} {} {} {}} {{} {} i 2 {} {} i 2 {} {} {} {} {} {}}}}
          518  +do_changeset_test $tn.9.2 S {{UPDATE t7 0 ....X.. {{} {} i 1 {} {} i 1 i 1 {} {} {} {}} {{} {} i 2 {} {} i 2 {} {} {} {} {} {}}}}
   504    519   S delete
   505    520   catch { db2 close }
   506    521    
   507    522   #-------------------------------------------------------------------------
   508    523   # Test a really long table name.
   509    524   #
   510    525   reset_db
   511    526   set tblname [string repeat tblname123 100]
   512         -do_test 10.1.1 {
          527  +do_test $tn.10.1.1 {
   513    528     execsql "
   514         -    CREATE TABLE $tblname (a PRIMARY KEY, b);
          529  +    CREATE TABLE $tblname (a PRIMARY KEY, b)%WR%;
   515    530       INSERT INTO $tblname VALUES('xyz', 'def');
   516    531     "
   517    532     sqlite3session S db main
   518    533     S attach $tblname
   519    534     execsql " 
   520    535       INSERT INTO $tblname VALUES('uvw', 'abc');
   521    536       DELETE FROM $tblname WHERE a = 'xyz';
   522    537     "
   523    538   } {}
   524    539   breakpoint
   525         -do_changeset_test 10.1.2 S "
          540  +do_changeset_test $tn.10.1.2 S "
   526    541     {INSERT $tblname 0 X. {} {t uvw t abc}}
   527    542     {DELETE $tblname 0 X. {t xyz t def} {}}
   528    543   "
   529         -do_test 10.1.4 { S delete } {}
          544  +do_test $tn.10.1.4 { S delete } {}
   530    545   
   531    546   #---------------------------------------------------------------
   532    547   reset_db
   533         -do_execsql_test 11.1 {
          548  +do_execsql_test $tn.11.1 {
   534    549     CREATE TABLE t1(a, b);
   535    550   }
   536         -do_test 11.2 {
          551  +do_test $tn.11.2 {
   537    552     sqlite3session S db main
   538    553     S attach t1
   539    554     execsql {
   540    555       INSERT INTO t1 VALUES(1, 2);
   541    556     }
   542    557     S changeset
   543    558   } {}
................................................................................
   546    561   
   547    562   
   548    563   #-------------------------------------------------------------------------
   549    564   # Test a really long table name.
   550    565   #
   551    566   reset_db
   552    567   set tblname [string repeat tblname123 100]
   553         -do_test 10.1.1 {
          568  +do_test $tn.10.1.1 {
   554    569     execsql "
   555         -    CREATE TABLE $tblname (a PRIMARY KEY, b);
          570  +    CREATE TABLE $tblname (a PRIMARY KEY, b)%WR%;
   556    571       INSERT INTO $tblname VALUES('xyz', 'def');
   557    572     "
   558    573     sqlite3session S db main
   559    574     S attach $tblname
   560    575     execsql " 
   561    576       INSERT INTO $tblname VALUES('uvw', 'abc');
   562    577       DELETE FROM $tblname WHERE a = 'xyz';
   563    578     "
   564    579   } {}
   565    580   breakpoint
   566         -do_changeset_test 10.1.2 S "
          581  +do_changeset_test $tn.10.1.2 S "
   567    582     {INSERT $tblname 0 X. {} {t uvw t abc}}
   568    583     {DELETE $tblname 0 X. {t xyz t def} {}}
   569    584   "
   570         -do_test 10.1.4 { S delete } {}
          585  +do_test $tn.10.1.4 { S delete } {}
   571    586   
   572    587   #-------------------------------------------------------------------------
   573    588   # Test the effect of updating a column from 0.0 to 0.0.
   574    589   #
   575    590   reset_db
   576         -do_execsql_test 11.1 {
   577         -  CREATE TABLE t1(a INTEGER PRIMARY KEY, b REAL);
          591  +do_execsql_test $tn.11.1 {
          592  +  CREATE TABLE t1(a INTEGER PRIMARY KEY, b REAL)%WR%;
   578    593     INSERT INTO t1 VALUES(1, 0.0);
   579    594   }
   580         -do_iterator_test 11.2 * {
          595  +do_iterator_test $tn.11.2 * {
   581    596     UPDATE t1 SET b = 0.0;
   582    597   } {
   583    598   }
   584    599   
   585    600   reset_db
   586         -do_execsql_test 12.1 {
   587         -  CREATE TABLE t1(r INTEGER PRIMARY KEY, a, b);
          601  +do_execsql_test $tn.12.1 {
          602  +  CREATE TABLE t1(r INTEGER PRIMARY KEY, a, b)%WR%;
   588    603     CREATE INDEX i1 ON t1(a);
   589    604     INSERT INTO t1 VALUES(1, 1, 1);
   590    605     INSERT INTO t1 VALUES(2, 1, 2);
   591    606     INSERT INTO t1 VALUES(3, 1, 3);
   592    607   }
   593    608   
   594         -do_iterator_test 12.2 * {
          609  +do_iterator_test $tn.12.2 * {
   595    610     UPDATE t1 SET b='one' WHERE a=1;
   596    611   } {
   597    612     {UPDATE t1 0 X.. {i 1 {} {} i 1} {{} {} {} {} t one}}
   598    613     {UPDATE t1 0 X.. {i 2 {} {} i 2} {{} {} {} {} t one}}
   599    614     {UPDATE t1 0 X.. {i 3 {} {} i 3} {{} {} {} {} t one}}
   600    615   }
   601    616   
          617  +}]
          618  +}
   602    619   
   603    620   
   604    621   finish_test

Added ext/session/sessionwor.test.

            1  +# 2017 Jan 31
            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. Specifically,
           13  +# testing support for WITHOUT ROWID tables.
           14  +#
           15  +
           16  +if {![info exists testdir]} {
           17  +  set testdir [file join [file dirname [info script]] .. .. test]
           18  +} 
           19  +source [file join [file dirname [info script]] session_common.tcl]
           20  +source $testdir/tester.tcl
           21  +ifcapable !session {finish_test; return}
           22  +
           23  +set testprefix sessionwor
           24  +
           25  +proc test_reset {} {
           26  +  catch { db close }
           27  +  catch { db2 close }
           28  +  forcedelete test.db test.db2
           29  +  sqlite3 db test.db
           30  +  sqlite3 db2 test.db2
           31  +}
           32  +
           33  +
           34  +do_execsql_test 1.0 {
           35  +  CREATE TABLE t1(a PRIMARY KEY, b) WITHOUT ROWID;
           36  +}
           37  +
           38  +do_iterator_test 1.1 t1 {
           39  +  INSERT INTO t1 VALUES('one', 'two');
           40  +} {
           41  +  {INSERT t1 0 X. {} {t one t two}}
           42  +}
           43  +
           44  +do_iterator_test 1.2 t1 {
           45  +  UPDATE t1 SET b='three'
           46  +} {
           47  +  {UPDATE t1 0 X. {t one t two} {{} {} t three}}
           48  +}
           49  +
           50  +do_iterator_test 1.3 t1 {
           51  +  DELETE FROM t1;
           52  +} {
           53  +  {DELETE t1 0 X. {t one t three} {}}
           54  +}
           55  +
           56  +finish_test
           57  +

Changes to src/insert.c.

  1726   1726     for(i=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, i++){
  1727   1727       if( aRegIdx[i]==0 ) continue;
  1728   1728       bAffinityDone = 1;
  1729   1729       if( pIdx->pPartIdxWhere ){
  1730   1730         sqlite3VdbeAddOp2(v, OP_IsNull, aRegIdx[i], sqlite3VdbeCurrentAddr(v)+2);
  1731   1731         VdbeCoverage(v);
  1732   1732       }
  1733         -    sqlite3VdbeAddOp4Int(v, OP_IdxInsert, iIdxCur+i, aRegIdx[i],
  1734         -                         aRegIdx[i]+1,
  1735         -                         pIdx->uniqNotNull ? pIdx->nKeyCol: pIdx->nColumn);
  1736         -    pik_flags = 0;
  1737         -    if( useSeekResult ) pik_flags = OPFLAG_USESEEKRESULT;
         1733  +    pik_flags = (useSeekResult ? OPFLAG_USESEEKRESULT : 0);
  1738   1734       if( IsPrimaryKeyIndex(pIdx) && !HasRowid(pTab) ){
  1739   1735         assert( pParse->nested==0 );
  1740   1736         pik_flags |= OPFLAG_NCHANGE;
  1741   1737         pik_flags |= (update_flags & OPFLAG_SAVEPOSITION);
         1738  +#ifdef SQLITE_ENABLE_PREUPDATE_HOOK
         1739  +      if( update_flags==0 ){
         1740  +        sqlite3VdbeAddOp4(v, OP_InsertInt, 
         1741  +            iIdxCur+i, aRegIdx[i], 0, (char*)pTab, P4_TABLE
         1742  +        );
         1743  +        sqlite3VdbeChangeP5(v, OPFLAG_ISNOOP);
         1744  +      }
         1745  +#endif
  1742   1746       }
         1747  +    sqlite3VdbeAddOp4Int(v, OP_IdxInsert, iIdxCur+i, aRegIdx[i],
         1748  +                         aRegIdx[i]+1,
         1749  +                         pIdx->uniqNotNull ? pIdx->nKeyCol: pIdx->nColumn);
  1743   1750       sqlite3VdbeChangeP5(v, pik_flags);
  1744   1751     }
  1745   1752     if( !HasRowid(pTab) ) return;
  1746   1753     regData = regNewData + 1;
  1747   1754     regRec = sqlite3GetTempReg(pParse);
  1748   1755     sqlite3VdbeAddOp3(v, OP_MakeRecord, regData, pTab->nCol, regRec);
  1749   1756     sqlite3SetMakeRecordP5(v, pTab);

Changes to src/vdbe.c.

  4380   4380     pData = &aMem[pOp->p2];
  4381   4381     assert( pOp->p1>=0 && pOp->p1<p->nCursor );
  4382   4382     assert( memIsValid(pData) );
  4383   4383     pC = p->apCsr[pOp->p1];
  4384   4384     assert( pC!=0 );
  4385   4385     assert( pC->eCurType==CURTYPE_BTREE );
  4386   4386     assert( pC->uc.pCursor!=0 );
  4387         -  assert( pC->isTable );
         4387  +  assert( (pOp->p5 & OPFLAG_ISNOOP) || pC->isTable );
  4388   4388     assert( pOp->p4type==P4_TABLE || pOp->p4type>=P4_STATIC );
  4389   4389     REGISTER_TRACE(pOp->p2, pData);
  4390   4390   
  4391   4391     if( pOp->opcode==OP_Insert ){
  4392   4392       pKey = &aMem[pOp->p3];
  4393   4393       assert( pKey->flags & MEM_Int );
  4394   4394       assert( memIsValid(pKey) );
................................................................................
  4396   4396       x.nKey = pKey->u.i;
  4397   4397     }else{
  4398   4398       assert( pOp->opcode==OP_InsertInt );
  4399   4399       x.nKey = pOp->p3;
  4400   4400     }
  4401   4401   
  4402   4402     if( pOp->p4type==P4_TABLE && HAS_UPDATE_HOOK(db) ){
  4403         -    assert( pC->isTable );
  4404   4403       assert( pC->iDb>=0 );
  4405   4404       zDb = db->aDb[pC->iDb].zDbSName;
  4406   4405       pTab = pOp->p4.pTab;
  4407         -    assert( HasRowid(pTab) );
         4406  +    assert( (pOp->p5 & OPFLAG_ISNOOP) || HasRowid(pTab) );
  4408   4407       op = ((pOp->p5 & OPFLAG_ISUPDATE) ? SQLITE_UPDATE : SQLITE_INSERT);
  4409   4408     }else{
  4410   4409       pTab = 0; /* Not needed.  Silence a comiler warning. */
  4411   4410       zDb = 0;  /* Not needed.  Silence a compiler warning. */
  4412   4411     }
  4413   4412   
  4414   4413   #ifdef SQLITE_ENABLE_PREUPDATE_HOOK
................................................................................
  4415   4414     /* Invoke the pre-update hook, if any */
  4416   4415     if( db->xPreUpdateCallback 
  4417   4416      && pOp->p4type==P4_TABLE
  4418   4417      && !(pOp->p5 & OPFLAG_ISUPDATE)
  4419   4418     ){
  4420   4419       sqlite3VdbePreUpdateHook(p, pC, SQLITE_INSERT, zDb, pTab, x.nKey, pOp->p2);
  4421   4420     }
         4421  +  if( pOp->p5 & OPFLAG_ISNOOP ) break;
  4422   4422   #endif
  4423   4423   
  4424   4424     if( pOp->p5 & OPFLAG_NCHANGE ) p->nChange++;
  4425   4425     if( pOp->p5 & OPFLAG_LASTROWID ) db->lastRowid = x.nKey;
  4426   4426     if( pData->flags & MEM_Null ){
  4427   4427       x.pData = 0;
  4428   4428       x.nData = 0;
................................................................................
  4527   4527     }else{
  4528   4528       zDb = 0;   /* Not needed.  Silence a compiler warning. */
  4529   4529       pTab = 0;  /* Not needed.  Silence a compiler warning. */
  4530   4530     }
  4531   4531   
  4532   4532   #ifdef SQLITE_ENABLE_PREUPDATE_HOOK
  4533   4533     /* Invoke the pre-update-hook if required. */
  4534         -  if( db->xPreUpdateCallback && pOp->p4.pTab && HasRowid(pTab) ){
  4535         -    assert( !(opflags & OPFLAG_ISUPDATE) || (aMem[pOp->p3].flags & MEM_Int) );
         4534  +  if( db->xPreUpdateCallback && pOp->p4.pTab ){
         4535  +    assert( !(opflags & OPFLAG_ISUPDATE) 
         4536  +         || HasRowid(pTab)==0 
         4537  +         || (aMem[pOp->p3].flags & MEM_Int) 
         4538  +    );
  4536   4539       sqlite3VdbePreUpdateHook(p, pC,
  4537   4540           (opflags & OPFLAG_ISUPDATE) ? SQLITE_UPDATE : SQLITE_DELETE, 
  4538   4541           zDb, pTab, pC->movetoTarget,
  4539   4542           pOp->p3
  4540   4543       );
  4541   4544     }
  4542   4545     if( opflags & OPFLAG_ISNOOP ) break;

Changes to src/vdbeInt.h.

   430    430     UnpackedRecord *pUnpacked;      /* Unpacked version of aRecord[] */
   431    431     UnpackedRecord *pNewUnpacked;   /* Unpacked version of new.* record */
   432    432     int iNewReg;                    /* Register for new.* values */
   433    433     i64 iKey1;                      /* First key value passed to hook */
   434    434     i64 iKey2;                      /* Second key value passed to hook */
   435    435     Mem *aNew;                      /* Array of new.* values */
   436    436     Table *pTab;                    /* Schema object being upated */          
          437  +  Index *pPk;                     /* PK index if pTab is WITHOUT ROWID */
   437    438   };
   438    439   
   439    440   /*
   440    441   ** Function prototypes
   441    442   */
   442    443   void sqlite3VdbeError(Vdbe*, const char *, ...);
   443    444   void sqlite3VdbeFreeCursor(Vdbe *, VdbeCursor*);

Changes to src/vdbeapi.c.

  1665   1665   
  1666   1666     /* Test that this call is being made from within an SQLITE_DELETE or
  1667   1667     ** SQLITE_UPDATE pre-update callback, and that iIdx is within range. */
  1668   1668     if( !p || p->op==SQLITE_INSERT ){
  1669   1669       rc = SQLITE_MISUSE_BKPT;
  1670   1670       goto preupdate_old_out;
  1671   1671     }
         1672  +  if( p->pPk ){
         1673  +    iIdx = sqlite3ColumnOfIndex(p->pPk, iIdx);
         1674  +  }
  1672   1675     if( iIdx>=p->pCsr->nField || iIdx<0 ){
  1673   1676       rc = SQLITE_RANGE;
  1674   1677       goto preupdate_old_out;
  1675   1678     }
  1676   1679   
  1677   1680     /* If the old.* record has not yet been loaded into memory, do so now. */
  1678   1681     if( p->pUnpacked==0 ){
................................................................................
  1750   1753     int rc = SQLITE_OK;
  1751   1754     Mem *pMem;
  1752   1755   
  1753   1756     if( !p || p->op==SQLITE_DELETE ){
  1754   1757       rc = SQLITE_MISUSE_BKPT;
  1755   1758       goto preupdate_new_out;
  1756   1759     }
         1760  +  if( p->pPk && p->op!=SQLITE_UPDATE ){
         1761  +    iIdx = sqlite3ColumnOfIndex(p->pPk, iIdx);
         1762  +  }
  1757   1763     if( iIdx>=p->pCsr->nField || iIdx<0 ){
  1758   1764       rc = SQLITE_RANGE;
  1759   1765       goto preupdate_new_out;
  1760   1766     }
  1761   1767   
  1762   1768     if( p->op==SQLITE_INSERT ){
  1763   1769       /* For an INSERT, memory cell p->iNewReg contains the serialized record

Changes to src/vdbeaux.c.

  4616   4616     i64 iKey2;
  4617   4617     PreUpdate preupdate;
  4618   4618     const char *zTbl = pTab->zName;
  4619   4619     static const u8 fakeSortOrder = 0;
  4620   4620   
  4621   4621     assert( db->pPreUpdate==0 );
  4622   4622     memset(&preupdate, 0, sizeof(PreUpdate));
  4623         -  if( op==SQLITE_UPDATE ){
  4624         -    iKey2 = v->aMem[iReg].u.i;
         4623  +  if( HasRowid(pTab)==0 ){
         4624  +    iKey1 = iKey2 = 0;
         4625  +    preupdate.pPk = sqlite3PrimaryKeyIndex(pTab);
  4625   4626     }else{
  4626         -    iKey2 = iKey1;
         4627  +    if( op==SQLITE_UPDATE ){
         4628  +      iKey2 = v->aMem[iReg].u.i;
         4629  +    }else{
         4630  +      iKey2 = iKey1;
         4631  +    }
  4627   4632     }
  4628   4633   
  4629   4634     assert( pCsr->nField==pTab->nCol 
  4630   4635          || (pCsr->nField==pTab->nCol+1 && op==SQLITE_DELETE && iReg==-1)
  4631   4636     );
  4632   4637   
  4633   4638     preupdate.v = v;

Added test/hook2.test.

            1  +# 2017 Jan 30
            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  +# The tests in this file focus on the pre-update hook.
           12  +# 
           13  +
           14  +set testdir [file dirname $argv0]
           15  +source $testdir/tester.tcl
           16  +set ::testprefix hook2
           17  +
           18  +ifcapable !preupdate {
           19  +  finish_test
           20  +  return
           21  +}
           22  +
           23  +#-------------------------------------------------------------------------
           24  +proc do_preupdate_test {tn sql x} {
           25  +  set X [list]
           26  +  foreach elem $x {lappend X $elem}
           27  +  uplevel do_test $tn [list "
           28  +    set ::preupdate \[list\]
           29  +    execsql { $sql }
           30  +    set ::preupdate
           31  +  "] [list $X]
           32  +}
           33  +
           34  +proc preupdate_hook {args} {
           35  +  set type [lindex $args 0]
           36  +  eval lappend ::preupdate $args
           37  +  if {$type != "INSERT"} {
           38  +    for {set i 0} {$i < [db preupdate count]} {incr i} {
           39  +      lappend ::preupdate [db preupdate old $i]
           40  +    }
           41  +  }
           42  +  if {$type != "DELETE"} {
           43  +    for {set i 0} {$i < [db preupdate count]} {incr i} {
           44  +      set rc [catch { db preupdate new $i } v]
           45  +      lappend ::preupdate $v
           46  +    }
           47  +  }
           48  +}
           49  +
           50  +#-------------------------------------------------------------------------
           51  +# Simple tests - INSERT, UPDATE and DELETE on a WITHOUT ROWID table.
           52  +#
           53  +db preupdate hook preupdate_hook
           54  +do_execsql_test 1.0 {
           55  +  CREATE TABLE t1(a PRIMARY KEY, b) WITHOUT ROWID;
           56  +}
           57  +do_preupdate_test 1.1 {
           58  +  INSERT INTO t1 VALUES('one', 1);
           59  +} {
           60  +  INSERT main t1 0 0  one 1
           61  +}
           62  +do_preupdate_test 1.2 {
           63  +  UPDATE t1 SET b=2 WHERE a='one';
           64  +} {
           65  +  UPDATE main t1 0 0  one 1 one 2
           66  +}
           67  +do_preupdate_test 1.3 {
           68  +  DELETE FROM t1 WHERE a='one';
           69  +} {
           70  +  DELETE main t1 0 0  one 2
           71  +}
           72  +
           73  +#-------------------------------------------------------------------------
           74  +# Some more complex tests for the pre-update callback on WITHOUT ROWID
           75  +# tables.
           76  +#
           77  +#   2.1.1 - INSERT statement.
           78  +#   2.1.2 - INSERT INTO ... SELECT statement.
           79  +#   2.1.3 - REPLACE INTO ... (PK conflict)
           80  +#   2.1.4 - REPLACE INTO ... (other index conflicts)
           81  +#   2.1.5 - REPLACE INTO ... (both PK and other index conflicts)
           82  +#
           83  +#   2.2.1 - DELETE statement.
           84  +#   2.2.2 - DELETE statement that uses the truncate optimization.
           85  +#
           86  +#   2.3.1 - UPDATE statement.
           87  +#   2.3.2 - UPDATE statement that modifies the PK.
           88  +#   2.3.3 - UPDATE OR REPLACE ... (PK conflict).
           89  +#   2.3.4 - UPDATE OR REPLACE ... (other index conflicts)
           90  +#   2.3.4 - UPDATE OR REPLACE ... (both PK and other index conflicts)
           91  +#
           92  +do_execsql_test 2.0 {
           93  +  CREATE TABLE t2(a DEFAULT 4, b, c, PRIMARY KEY(b, c)) WITHOUT ROWID;
           94  +  CREATE UNIQUE INDEX t2a ON t2(a);
           95  +}
           96  +
           97  +do_preupdate_test 2.1.1 {
           98  +  INSERT INTO t2(b, c) VALUES(1, 1);
           99  +} {
          100  +  INSERT main t2 0 0  4 1 1
          101  +}
          102  +
          103  +do_execsql_test 2.1.2.0 {
          104  +  CREATE TABLE d1(a DEFAULT 4, b, c, PRIMARY KEY(b, c)) WITHOUT ROWID;
          105  +  CREATE UNIQUE INDEX d1a ON d1(a);
          106  +  INSERT INTO d1 VALUES(1, 2, 3);
          107  +  INSERT INTO d1 VALUES(11, 12, 13);
          108  +}
          109  +do_preupdate_test 2.1.2.1 {
          110  +  INSERT INTO t2 SELECT * FROM d1;
          111  +} {
          112  +  INSERT main t2 0 0  1 2 3
          113  +  INSERT main t2 0 0  11 12 13
          114  +}
          115  +do_preupdate_test 2.1.2.2 {
          116  +  INSERT INTO t2 SELECT a+20, b+20, c+20 FROM d1;
          117  +} {
          118  +  INSERT main t2 0 0  21 22 23
          119  +  INSERT main t2 0 0  31 32 33
          120  +}
          121  +do_execsql_test 2.1.2.3 {
          122  +  SELECT * FROM t2 ORDER BY b, c;
          123  +} {
          124  +  4 1 1
          125  +  1 2 3
          126  +  11 12 13
          127  +  21 22 23
          128  +  31 32 33
          129  +}
          130  +do_preupdate_test 2.1.3 {
          131  +  REPLACE INTO t2 VALUES(45, 22, 23);
          132  +} {
          133  +  DELETE main t2 0 0 21 22 23
          134  +  INSERT main t2 0 0 45 22 23
          135  +}
          136  +do_preupdate_test 2.1.4 {
          137  +  REPLACE INTO t2 VALUES(11, 100, 100);
          138  +} {
          139  +  DELETE main t2 0 0 11 12 13
          140  +  INSERT main t2 0 0 11 100 100
          141  +}
          142  +do_preupdate_test 2.1.5 {
          143  +  REPLACE INTO t2(c, b) VALUES(33, 32)
          144  +} {
          145  +  DELETE main t2 0 0 4 1 1 
          146  +  DELETE main t2 0 0 31 32 33
          147  +  INSERT main t2 0 0 4 32 33
          148  +}
          149  +
          150  +do_execsql_test 2.2.0 {
          151  +  SELECT * FROM t2 ORDER BY b,c;
          152  +} {
          153  +  1    2   3 
          154  +  45  22  23 
          155  +  4   32  33 
          156  +  11 100 100
          157  +}
          158  +do_preupdate_test 2.2.1 {
          159  +  DELETE FROM t2 WHERE b=22;
          160  +} {
          161  +  DELETE main t2 0 0  45 22 23
          162  +}
          163  +do_preupdate_test 2.2.2 {
          164  +  DELETE FROM t2;
          165  +} {
          166  +  DELETE main t2 0 0 1 2 3 
          167  +  DELETE main t2 0 0 4 32 33 
          168  +  DELETE main t2 0 0 11 100 100
          169  +}
          170  +
          171  +do_execsql_test 2.3.0 {
          172  +  CREATE TABLE t3(x, y PRIMARY KEY, z UNIQUE) WITHOUT ROWID;
          173  +  INSERT INTO t3 VALUES('a', 'b', 'c');
          174  +  INSERT INTO t3 VALUES('d', 'e', 'f');
          175  +
          176  +  INSERT INTO t3 VALUES(1, 1, 1);
          177  +  INSERT INTO t3 VALUES(2, 2, 2);
          178  +  INSERT INTO t3 VALUES(3, 3, 3);
          179  +}
          180  +
          181  +do_preupdate_test 2.3.1 {
          182  +  UPDATE t3 SET x=4 WHERE y IN ('b', 'e', 'x');
          183  +} {
          184  +  UPDATE main t3 0 0  a b c   4 b c
          185  +  UPDATE main t3 0 0  d e f   4 e f
          186  +}
          187  +
          188  +do_preupdate_test 2.3.2 {
          189  +  UPDATE t3 SET y=y||y WHERE z IN('c', 'f');
          190  +} {
          191  +  UPDATE main t3 0 0  4 b c   4 bb c
          192  +  UPDATE main t3 0 0  4 e f   4 ee f
          193  +}
          194  +
          195  +do_preupdate_test 2.3.3 {
          196  +  UPDATE OR REPLACE t3 SET y='bb' WHERE z='f'
          197  +} {
          198  +  DELETE main t3 0 0  4 bb c
          199  +  UPDATE main t3 0 0  4 ee f   4 bb f
          200  +}
          201  +
          202  +do_preupdate_test 2.3.4 {
          203  +  UPDATE OR REPLACE t3 SET z=2 WHERE y=1;
          204  +} {
          205  +  DELETE main t3 0 0  2 2 2
          206  +  UPDATE main t3 0 0  1 1 1  1 1 2
          207  +}
          208  +
          209  +do_preupdate_test 2.3.5 {
          210  +  UPDATE OR REPLACE t3 SET z=2, y='bb' WHERE y=3;
          211  +} {
          212  +  DELETE main t3 0 0  1 1 2
          213  +  DELETE main t3 0 0  4 bb f
          214  +  UPDATE main t3 0 0  3 3 3  3 bb 2
          215  +}
          216  +  
          217  +
          218  +finish_test