000001  # The author disclaims copyright to this source code.  In place of
000002  # a legal notice, here is a blessing:
000003  #
000004  #    May you do good and not evil.
000005  #    May you find forgiveness for yourself and forgive others.
000006  #    May you share freely, never taking more than you give.
000007  #
000008  #***********************************************************************
000009  #
000010  # Tests to make sure that value returned by last_insert_rowid() (LIRID)
000011  # is updated properly, especially inside triggers
000012  #
000013  # Note 1: insert into table is now the only statement which changes LIRID
000014  # Note 2: upon entry into before or instead of triggers,
000015  #           LIRID is unchanged (rather than -1)
000016  # Note 3: LIRID is changed within the context of a trigger,
000017  #           but is restored once the trigger exits
000018  # Note 4: LIRID is not changed by an insert into a view (since everything
000019  #           is done within instead of trigger context)
000020  #
000021  
000022  set testdir [file dirname $argv0]
000023  source $testdir/tester.tcl
000024  
000025  # ----------------------------------------------------------------------------
000026  # 1.x - basic tests (no triggers)
000027  
000028  # LIRID changed properly after an insert into a table
000029  do_test lastinsert-1.1 {
000030      catchsql {
000031          create table t1 (k integer primary key);
000032          insert into t1 values (1);
000033          insert into t1 values (NULL);
000034          insert into t1 values (NULL);
000035          select last_insert_rowid();
000036      }
000037  } {0 3}
000038  
000039  # EVIDENCE-OF: R-47220-63683 The sqlite3_last_insert_rowid() function
000040  # does not work for WITHOUT ROWID tables.
000041  #
000042  do_test lastinsert-1.1w {
000043      catchsql {
000044          create table t1w (k integer primary key) WITHOUT ROWID;
000045          insert into t1w values (123456);
000046          select last_insert_rowid(); -- returns 3 from above.
000047      }
000048  } {0 3}
000049  
000050  # LIRID unchanged after an update on a table
000051  do_test lastinsert-1.2 {
000052      catchsql {
000053          update t1 set k=4 where k=2;
000054          select last_insert_rowid();
000055      }
000056  } {0 3}
000057  
000058  # LIRID unchanged after a delete from a table
000059  do_test lastinsert-1.3 {
000060      catchsql {
000061          delete from t1 where k=4;
000062          select last_insert_rowid();
000063      }
000064  } {0 3}
000065  
000066  # LIRID unchanged after create table/view statements
000067  do_test lastinsert-1.4.1 {
000068      catchsql {
000069          create table t2 (k integer primary key, val1, val2, val3);
000070          select last_insert_rowid();
000071      }
000072  } {0 3}
000073  ifcapable view {
000074  do_test lastinsert-1.4.2 {
000075      catchsql {
000076          create view v as select * from t1;
000077          select last_insert_rowid();
000078      }
000079  } {0 3}
000080  } ;# ifcapable view
000081  
000082  # All remaining tests involve triggers.  Skip them if triggers are not
000083  # supported in this build.
000084  #
000085  ifcapable {!trigger} {
000086    finish_test
000087    return
000088  }
000089  
000090  # ----------------------------------------------------------------------------
000091  # 2.x - tests with after insert trigger
000092  
000093  # LIRID changed properly after an insert into table containing an after trigger
000094  do_test lastinsert-2.1 {
000095      catchsql {
000096          delete from t2;
000097          create trigger r1 after insert on t1 for each row begin
000098              insert into t2 values (NEW.k*2, last_insert_rowid(), NULL, NULL);
000099              update t2 set k=k+10, val2=100+last_insert_rowid();
000100              update t2 set val3=1000+last_insert_rowid();
000101          end;
000102          insert into t1 values (13);
000103          select last_insert_rowid();
000104      }
000105  } {0 13}
000106  
000107  # LIRID equals NEW.k upon entry into after insert trigger
000108  do_test lastinsert-2.2 {
000109      catchsql {
000110          select val1 from t2;
000111      }
000112  } {0 13}
000113  
000114  # LIRID changed properly by insert within context of after insert trigger
000115  do_test lastinsert-2.3 {
000116      catchsql {
000117          select val2 from t2;
000118      }
000119  } {0 126}
000120  
000121  # LIRID unchanged by update within context of after insert trigger
000122  do_test lastinsert-2.4 {
000123      catchsql {
000124          select val3 from t2;
000125      }
000126  } {0 1026}
000127  
000128  # ----------------------------------------------------------------------------
000129  # 3.x - tests with after update trigger
000130  
000131  # LIRID not changed after an update onto a table containing an after trigger
000132  do_test lastinsert-3.1 {
000133      catchsql {
000134          delete from t2;
000135          drop trigger r1;
000136          create trigger r1 after update on t1 for each row begin
000137              insert into t2 values (NEW.k*2, last_insert_rowid(), NULL, NULL);
000138              update t2 set k=k+10, val2=100+last_insert_rowid();
000139              update t2 set val3=1000+last_insert_rowid();
000140          end;
000141          update t1 set k=14 where k=3;
000142          select last_insert_rowid();
000143      }
000144  } {0 13}
000145  
000146  # LIRID unchanged upon entry into after update trigger
000147  do_test lastinsert-3.2 {
000148      catchsql {
000149          select val1 from t2;
000150      }
000151  } {0 13}
000152  
000153  # LIRID changed properly by insert within context of after update trigger
000154  do_test lastinsert-3.3 {
000155      catchsql {
000156          select val2 from t2;
000157      }
000158  } {0 128}
000159  
000160  # LIRID unchanged by update within context of after update trigger
000161  do_test lastinsert-3.4 {
000162      catchsql {
000163          select val3 from t2;
000164      }
000165  } {0 1028}
000166  
000167  # ----------------------------------------------------------------------------
000168  # 4.x - tests with instead of insert trigger
000169  # These may not be run if either views or triggers were disabled at 
000170  # compile-time
000171  
000172  ifcapable {view && trigger} {
000173  # LIRID not changed after an insert into view containing an instead of trigger
000174  do_test lastinsert-4.1 {
000175      catchsql {
000176          delete from t2;
000177          drop trigger r1;
000178          create trigger r1 instead of insert on v for each row begin
000179              insert into t2 values (NEW.k*2, last_insert_rowid(), NULL, NULL);
000180              update t2 set k=k+10, val2=100+last_insert_rowid();
000181              update t2 set val3=1000+last_insert_rowid();
000182          end;
000183          insert into v values (15);
000184          select last_insert_rowid();
000185      }
000186  } {0 13}
000187  
000188  # LIRID unchanged upon entry into instead of trigger
000189  do_test lastinsert-4.2 {
000190      catchsql {
000191          select val1 from t2;
000192      }
000193  } {0 13}
000194  
000195  # LIRID changed properly by insert within context of instead of trigger
000196  do_test lastinsert-4.3 {
000197      catchsql {
000198          select val2 from t2;
000199      }
000200  } {0 130}
000201  
000202  # LIRID unchanged by update within context of instead of trigger
000203  do_test lastinsert-4.4 {
000204      catchsql {
000205          select val3 from t2;
000206      }
000207  } {0 1030}
000208  } ;# ifcapable (view && trigger)
000209  
000210  # ----------------------------------------------------------------------------
000211  # 5.x - tests with before delete trigger
000212  
000213  # LIRID not changed after a delete on a table containing a before trigger
000214  do_test lastinsert-5.1 {
000215      catchsql {
000216        drop trigger r1;  -- This was not created if views are disabled.
000217      }
000218      catchsql {
000219          delete from t2;
000220          create trigger r1 before delete on t1 for each row begin
000221              insert into t2 values (77, last_insert_rowid(), NULL, NULL);
000222              update t2 set k=k+10, val2=100+last_insert_rowid();
000223              update t2 set val3=1000+last_insert_rowid();
000224          end;
000225          delete from t1 where k=1;
000226          select last_insert_rowid();
000227      }
000228  } {0 13}
000229  
000230  # LIRID unchanged upon entry into delete trigger
000231  do_test lastinsert-5.2 {
000232      catchsql {
000233          select val1 from t2;
000234      }
000235  } {0 13}
000236  
000237  # LIRID changed properly by insert within context of delete trigger
000238  do_test lastinsert-5.3 {
000239      catchsql {
000240          select val2 from t2;
000241      }
000242  } {0 177}
000243  
000244  # LIRID unchanged by update within context of delete trigger
000245  do_test lastinsert-5.4 {
000246      catchsql {
000247          select val3 from t2;
000248      }
000249  } {0 1077}
000250  
000251  # ----------------------------------------------------------------------------
000252  # 6.x - tests with instead of update trigger
000253  # These tests may not run if either views or triggers are disabled.
000254  
000255  ifcapable {view && trigger} {
000256  # LIRID not changed after an update on a view containing an instead of trigger
000257  do_test lastinsert-6.1 {
000258      catchsql {
000259          delete from t2;
000260          drop trigger r1;
000261          create trigger r1 instead of update on v for each row begin
000262              insert into t2 values (NEW.k*2, last_insert_rowid(), NULL, NULL);
000263              update t2 set k=k+10, val2=100+last_insert_rowid();
000264              update t2 set val3=1000+last_insert_rowid();
000265          end;
000266          update v set k=16 where k=14;
000267          select last_insert_rowid();
000268      }
000269  } {0 13}
000270  
000271  # LIRID unchanged upon entry into instead of trigger
000272  do_test lastinsert-6.2 {
000273      catchsql {
000274          select val1 from t2;
000275      }
000276  } {0 13}
000277  
000278  # LIRID changed properly by insert within context of instead of trigger
000279  do_test lastinsert-6.3 {
000280      catchsql {
000281          select val2 from t2;
000282      }
000283  } {0 132}
000284  
000285  # LIRID unchanged by update within context of instead of trigger
000286  do_test lastinsert-6.4 {
000287      catchsql {
000288          select val3 from t2;
000289      }
000290  } {0 1032}
000291  } ;# ifcapable (view && trigger)
000292  
000293  # ----------------------------------------------------------------------------
000294  # 7.x - complex tests with temporary tables and nested instead of triggers
000295  # These do not run if views or triggers are disabled.
000296  
000297  ifcapable {trigger && view && tempdb} {
000298  do_test lastinsert-7.1 {
000299      catchsql {
000300          drop table t1; drop table t2; drop trigger r1;
000301          create temp table t1 (k integer primary key);
000302          create temp table t2 (k integer primary key);
000303          create temp view v1 as select * from t1;
000304          create temp view v2 as select * from t2;
000305          create temp table rid (k integer primary key, rin, rout);
000306          insert into rid values (1, NULL, NULL);
000307          insert into rid values (2, NULL, NULL);
000308          create temp trigger r1 instead of insert on v1 for each row begin
000309              update rid set rin=last_insert_rowid() where k=1;
000310              insert into t1 values (100+NEW.k);
000311              insert into v2 values (100+last_insert_rowid());
000312              update rid set rout=last_insert_rowid() where k=1;
000313          end;
000314          create temp trigger r2 instead of insert on v2 for each row begin
000315              update rid set rin=last_insert_rowid() where k=2;
000316              insert into t2 values (1000+NEW.k);
000317              update rid set rout=last_insert_rowid() where k=2;
000318          end;
000319          insert into t1 values (77);
000320          select last_insert_rowid();
000321      }
000322  } {0 77}
000323  
000324  do_test lastinsert-7.2 {
000325      catchsql {
000326          insert into v1 values (5);
000327          select last_insert_rowid();
000328      }
000329  } {0 77}
000330  
000331  do_test lastinsert-7.3 {
000332      catchsql {
000333          select rin from rid where k=1;
000334      }
000335  } {0 77}
000336  
000337  do_test lastinsert-7.4 {
000338      catchsql {
000339          select rout from rid where k=1;
000340      }
000341  } {0 105}
000342  
000343  do_test lastinsert-7.5 {
000344      catchsql {
000345          select rin from rid where k=2;
000346      }
000347  } {0 105}
000348  
000349  do_test lastinsert-7.6 {
000350      catchsql {
000351          select rout from rid where k=2;
000352      }
000353  } {0 1205}
000354  
000355  do_test lastinsert-8.1 {
000356    db close
000357    sqlite3 db test.db
000358    execsql {
000359      CREATE TABLE t2(x INTEGER PRIMARY KEY, y);
000360      CREATE TABLE t3(a, b);
000361      CREATE TRIGGER after_t2 AFTER INSERT ON t2 BEGIN
000362        INSERT INTO t3 VALUES(new.x, new.y);
000363      END;
000364      INSERT INTO t2 VALUES(5000000000, 1);
000365      SELECT last_insert_rowid();
000366    }
000367  } 5000000000
000368  
000369  do_test lastinsert-9.1 {
000370    db eval {INSERT INTO t2 VALUES(123456789012345,0)}
000371    db last_insert_rowid
000372  } {123456789012345}
000373  
000374  
000375  } ;# ifcapable (view && trigger)
000376  
000377  finish_test