1 # The author disclaims copyright to this source code. In place of 2 # a legal notice, here is a blessing: 3 # 4 # May you do good and not evil. 5 # May you find forgiveness for yourself and forgive others. 6 # May you share freely, never taking more than you give. 7 # 8 #*********************************************************************** 9 # 10 # Tests to make sure that value returned by last_insert_rowid() (LIRID) 11 # is updated properly, especially inside triggers 12 # 13 # Note 1: insert into table is now the only statement which changes LIRID 14 # Note 2: upon entry into before or instead of triggers, 15 # LIRID is unchanged (rather than -1) 16 # Note 3: LIRID is changed within the context of a trigger, 17 # but is restored once the trigger exits 18 # Note 4: LIRID is not changed by an insert into a view (since everything 19 # is done within instead of trigger context) 20 # 21 22 set testdir [file dirname $argv0] 23 source $testdir/tester.tcl 24 25 # ---------------------------------------------------------------------------- 26 # 1.x - basic tests (no triggers) 27 28 # LIRID changed properly after an insert into a table 29 do_test lastinsert-1.1 { 30 catchsql { 31 create table t1 (k integer primary key); 32 insert into t1 values (1); 33 insert into t1 values (NULL); 34 insert into t1 values (NULL); 35 select last_insert_rowid(); 36 } 37 } {0 3} 38 39 # LIRID unchanged after an update on a table 40 do_test lastinsert-1.2 { 41 catchsql { 42 update t1 set k=4 where k=2; 43 select last_insert_rowid(); 44 } 45 } {0 3} 46 47 # LIRID unchanged after a delete from a table 48 do_test lastinsert-1.3 { 49 catchsql { 50 delete from t1 where k=4; 51 select last_insert_rowid(); 52 } 53 } {0 3} 54 55 # LIRID unchanged after create table/view statements 56 do_test lastinsert-1.4.1 { 57 catchsql { 58 create table t2 (k integer primary key, val1, val2, val3); 59 select last_insert_rowid(); 60 } 61 } {0 3} 62 ifcapable view { 63 do_test lastinsert-1.4.2 { 64 catchsql { 65 create view v as select * from t1; 66 select last_insert_rowid(); 67 } 68 } {0 3} 69 } ;# ifcapable view 70 71 # All remaining tests involve triggers. Skip them if triggers are not 72 # supported in this build. 73 # 74 ifcapable {!trigger} { 75 finish_test 76 return 77 } 78 79 # ---------------------------------------------------------------------------- 80 # 2.x - tests with after insert trigger 81 82 # LIRID changed properly after an insert into table containing an after trigger 83 do_test lastinsert-2.1 { 84 catchsql { 85 delete from t2; 86 create trigger r1 after insert on t1 for each row begin 87 insert into t2 values (NEW.k*2, last_insert_rowid(), NULL, NULL); 88 update t2 set k=k+10, val2=100+last_insert_rowid(); 89 update t2 set val3=1000+last_insert_rowid(); 90 end; 91 insert into t1 values (13); 92 select last_insert_rowid(); 93 } 94 } {0 13} 95 96 # LIRID equals NEW.k upon entry into after insert trigger 97 do_test lastinsert-2.2 { 98 catchsql { 99 select val1 from t2; 100 } 101 } {0 13} 102 103 # LIRID changed properly by insert within context of after insert trigger 104 do_test lastinsert-2.3 { 105 catchsql { 106 select val2 from t2; 107 } 108 } {0 126} 109 110 # LIRID unchanged by update within context of after insert trigger 111 do_test lastinsert-2.4 { 112 catchsql { 113 select val3 from t2; 114 } 115 } {0 1026} 116 117 # ---------------------------------------------------------------------------- 118 # 3.x - tests with after update trigger 119 120 # LIRID not changed after an update onto a table containing an after trigger 121 do_test lastinsert-3.1 { 122 catchsql { 123 delete from t2; 124 drop trigger r1; 125 create trigger r1 after update on t1 for each row begin 126 insert into t2 values (NEW.k*2, last_insert_rowid(), NULL, NULL); 127 update t2 set k=k+10, val2=100+last_insert_rowid(); 128 update t2 set val3=1000+last_insert_rowid(); 129 end; 130 update t1 set k=14 where k=3; 131 select last_insert_rowid(); 132 } 133 } {0 13} 134 135 # LIRID unchanged upon entry into after update trigger 136 do_test lastinsert-3.2 { 137 catchsql { 138 select val1 from t2; 139 } 140 } {0 13} 141 142 # LIRID changed properly by insert within context of after update trigger 143 do_test lastinsert-3.3 { 144 catchsql { 145 select val2 from t2; 146 } 147 } {0 128} 148 149 # LIRID unchanged by update within context of after update trigger 150 do_test lastinsert-3.4 { 151 catchsql { 152 select val3 from t2; 153 } 154 } {0 1028} 155 156 # ---------------------------------------------------------------------------- 157 # 4.x - tests with instead of insert trigger 158 # These may not be run if either views or triggers were disabled at 159 # compile-time 160 161 ifcapable {view && trigger} { 162 # LIRID not changed after an insert into view containing an instead of trigger 163 do_test lastinsert-4.1 { 164 catchsql { 165 delete from t2; 166 drop trigger r1; 167 create trigger r1 instead of insert on v for each row begin 168 insert into t2 values (NEW.k*2, last_insert_rowid(), NULL, NULL); 169 update t2 set k=k+10, val2=100+last_insert_rowid(); 170 update t2 set val3=1000+last_insert_rowid(); 171 end; 172 insert into v values (15); 173 select last_insert_rowid(); 174 } 175 } {0 13} 176 177 # LIRID unchanged upon entry into instead of trigger 178 do_test lastinsert-4.2 { 179 catchsql { 180 select val1 from t2; 181 } 182 } {0 13} 183 184 # LIRID changed properly by insert within context of instead of trigger 185 do_test lastinsert-4.3 { 186 catchsql { 187 select val2 from t2; 188 } 189 } {0 130} 190 191 # LIRID unchanged by update within context of instead of trigger 192 do_test lastinsert-4.4 { 193 catchsql { 194 select val3 from t2; 195 } 196 } {0 1030} 197 } ;# ifcapable (view && trigger) 198 199 # ---------------------------------------------------------------------------- 200 # 5.x - tests with before delete trigger 201 202 # LIRID not changed after a delete on a table containing a before trigger 203 do_test lastinsert-5.1 { 204 catchsql { 205 drop trigger r1; -- This was not created if views are disabled. 206 } 207 catchsql { 208 delete from t2; 209 create trigger r1 before delete on t1 for each row begin 210 insert into t2 values (77, last_insert_rowid(), NULL, NULL); 211 update t2 set k=k+10, val2=100+last_insert_rowid(); 212 update t2 set val3=1000+last_insert_rowid(); 213 end; 214 delete from t1 where k=1; 215 select last_insert_rowid(); 216 } 217 } {0 13} 218 219 # LIRID unchanged upon entry into delete trigger 220 do_test lastinsert-5.2 { 221 catchsql { 222 select val1 from t2; 223 } 224 } {0 13} 225 226 # LIRID changed properly by insert within context of delete trigger 227 do_test lastinsert-5.3 { 228 catchsql { 229 select val2 from t2; 230 } 231 } {0 177} 232 233 # LIRID unchanged by update within context of delete trigger 234 do_test lastinsert-5.4 { 235 catchsql { 236 select val3 from t2; 237 } 238 } {0 1077} 239 240 # ---------------------------------------------------------------------------- 241 # 6.x - tests with instead of update trigger 242 # These tests may not run if either views or triggers are disabled. 243 244 ifcapable {view && trigger} { 245 # LIRID not changed after an update on a view containing an instead of trigger 246 do_test lastinsert-6.1 { 247 catchsql { 248 delete from t2; 249 drop trigger r1; 250 create trigger r1 instead of update on v for each row begin 251 insert into t2 values (NEW.k*2, last_insert_rowid(), NULL, NULL); 252 update t2 set k=k+10, val2=100+last_insert_rowid(); 253 update t2 set val3=1000+last_insert_rowid(); 254 end; 255 update v set k=16 where k=14; 256 select last_insert_rowid(); 257 } 258 } {0 13} 259 260 # LIRID unchanged upon entry into instead of trigger 261 do_test lastinsert-6.2 { 262 catchsql { 263 select val1 from t2; 264 } 265 } {0 13} 266 267 # LIRID changed properly by insert within context of instead of trigger 268 do_test lastinsert-6.3 { 269 catchsql { 270 select val2 from t2; 271 } 272 } {0 132} 273 274 # LIRID unchanged by update within context of instead of trigger 275 do_test lastinsert-6.4 { 276 catchsql { 277 select val3 from t2; 278 } 279 } {0 1032} 280 } ;# ifcapable (view && trigger) 281 282 # ---------------------------------------------------------------------------- 283 # 7.x - complex tests with temporary tables and nested instead of triggers 284 # These do not run if views or triggers are disabled. 285 286 ifcapable {trigger && view && tempdb} { 287 do_test lastinsert-7.1 { 288 catchsql { 289 drop table t1; drop table t2; drop trigger r1; 290 create temp table t1 (k integer primary key); 291 create temp table t2 (k integer primary key); 292 create temp view v1 as select * from t1; 293 create temp view v2 as select * from t2; 294 create temp table rid (k integer primary key, rin, rout); 295 insert into rid values (1, NULL, NULL); 296 insert into rid values (2, NULL, NULL); 297 create temp trigger r1 instead of insert on v1 for each row begin 298 update rid set rin=last_insert_rowid() where k=1; 299 insert into t1 values (100+NEW.k); 300 insert into v2 values (100+last_insert_rowid()); 301 update rid set rout=last_insert_rowid() where k=1; 302 end; 303 create temp trigger r2 instead of insert on v2 for each row begin 304 update rid set rin=last_insert_rowid() where k=2; 305 insert into t2 values (1000+NEW.k); 306 update rid set rout=last_insert_rowid() where k=2; 307 end; 308 insert into t1 values (77); 309 select last_insert_rowid(); 310 } 311 } {0 77} 312 313 do_test lastinsert-7.2 { 314 catchsql { 315 insert into v1 values (5); 316 select last_insert_rowid(); 317 } 318 } {0 77} 319 320 do_test lastinsert-7.3 { 321 catchsql { 322 select rin from rid where k=1; 323 } 324 } {0 77} 325 326 do_test lastinsert-7.4 { 327 catchsql { 328 select rout from rid where k=1; 329 } 330 } {0 105} 331 332 do_test lastinsert-7.5 { 333 catchsql { 334 select rin from rid where k=2; 335 } 336 } {0 105} 337 338 do_test lastinsert-7.6 { 339 catchsql { 340 select rout from rid where k=2; 341 } 342 } {0 1205} 343 344 do_test lastinsert-8.1 { 345 db close 346 sqlite3 db test.db 347 execsql { 348 CREATE TABLE t2(x INTEGER PRIMARY KEY, y); 349 CREATE TABLE t3(a, b); 350 CREATE TRIGGER after_t2 AFTER INSERT ON t2 BEGIN 351 INSERT INTO t3 VALUES(new.x, new.y); 352 END; 353 INSERT INTO t2 VALUES(5000000000, 1); 354 SELECT last_insert_rowid(); 355 } 356 } 5000000000 357 358 do_test lastinsert-9.1 { 359 db eval {INSERT INTO t2 VALUES(123456789012345,0)} 360 db last_insert_rowid 361 } {123456789012345} 362 363 364 } ;# ifcapable (view && trigger) 365 366 finish_test 367