1b3c16b89Sdan# 2008 October 6 2b3c16b89Sdan# 3b3c16b89Sdan# The author disclaims copyright to this source code. In place of 4b3c16b89Sdan# a legal notice, here is a blessing: 5b3c16b89Sdan# 6b3c16b89Sdan# May you do good and not evil. 7b3c16b89Sdan# May you find forgiveness for yourself and forgive others. 8b3c16b89Sdan# May you share freely, never taking more than you give. 9b3c16b89Sdan# 10b3c16b89Sdan#*********************************************************************** 11b3c16b89Sdan# This file implements regression tests for SQLite library. The 12b3c16b89Sdan# focus of this file is testing the LIMIT ... OFFSET ... clause 13b3c16b89Sdan# of UPDATE and DELETE statements. 14b3c16b89Sdan# 15b3c16b89Sdan 16b3c16b89Sdanset testdir [file dirname $argv0] 17b3c16b89Sdansource $testdir/tester.tcl 18b3c16b89Sdanset testprefix wherelimit2 19b3c16b89Sdan 20b3c16b89Sdanifcapable !update_delete_limit { 21b3c16b89Sdan finish_test 22b3c16b89Sdan return 23b3c16b89Sdan} 24b3c16b89Sdan 2526caf5beSdan#------------------------------------------------------------------------- 2626caf5beSdan# Test with views and INSTEAD OF triggers. 2726caf5beSdan# 28b3c16b89Sdando_execsql_test 1.0 { 29b3c16b89Sdan CREATE TABLE t1(a, b); 30b3c16b89Sdan INSERT INTO t1 VALUES(1, 'f'); 31b3c16b89Sdan INSERT INTO t1 VALUES(2, 'e'); 32b3c16b89Sdan INSERT INTO t1 VALUES(3, 'd'); 33b3c16b89Sdan INSERT INTO t1 VALUES(4, 'c'); 34b3c16b89Sdan INSERT INTO t1 VALUES(5, 'b'); 35b3c16b89Sdan INSERT INTO t1 VALUES(6, 'a'); 36b3c16b89Sdan 37b3c16b89Sdan CREATE VIEW v1 AS SELECT a,b FROM t1; 38b3c16b89Sdan CREATE TABLE log(op, a); 39b3c16b89Sdan 40b3c16b89Sdan CREATE TRIGGER v1del INSTEAD OF DELETE ON v1 BEGIN 41b3c16b89Sdan INSERT INTO log VALUES('delete', old.a); 42b3c16b89Sdan END; 43b3c16b89Sdan 44b3c16b89Sdan CREATE TRIGGER v1upd INSTEAD OF UPDATE ON v1 BEGIN 45b3c16b89Sdan INSERT INTO log VALUES('update', old.a); 46b3c16b89Sdan END; 47b3c16b89Sdan} 48b3c16b89Sdan 49b3c16b89Sdando_execsql_test 1.1 { 50b3c16b89Sdan DELETE FROM v1 ORDER BY a LIMIT 3; 51b3c16b89Sdan SELECT * FROM log; DELETE FROM log; 52b3c16b89Sdan} { 53b3c16b89Sdan delete 1 delete 2 delete 3 54b3c16b89Sdan} 55b3c16b89Sdando_execsql_test 1.2 { 56b3c16b89Sdan DELETE FROM v1 ORDER BY b LIMIT 3; 57b3c16b89Sdan SELECT * FROM log; DELETE FROM log; 58b3c16b89Sdan} { 59b3c16b89Sdan delete 6 delete 5 delete 4 60b3c16b89Sdan} 61b3c16b89Sdando_execsql_test 1.3 { 62b3c16b89Sdan UPDATE v1 SET b = 555 ORDER BY a LIMIT 3; 63b3c16b89Sdan SELECT * FROM log; DELETE FROM log; 64b3c16b89Sdan} { 65b3c16b89Sdan update 1 update 2 update 3 66b3c16b89Sdan} 67b3c16b89Sdando_execsql_test 1.4 { 68b3c16b89Sdan UPDATE v1 SET b = 555 ORDER BY b LIMIT 3; 69b3c16b89Sdan SELECT * FROM log; DELETE FROM log; 70b3c16b89Sdan} { 71b3c16b89Sdan update 6 update 5 update 4 72b3c16b89Sdan} 73b3c16b89Sdan 7426caf5beSdan#------------------------------------------------------------------------- 7526caf5beSdan# Simple test using WITHOUT ROWID table. 7626caf5beSdan# 77ca3e3c3fSdando_execsql_test 2.1.0 { 78b3c16b89Sdan CREATE TABLE t2(a, b, c, PRIMARY KEY(a, b)) WITHOUT ROWID; 79b3c16b89Sdan INSERT INTO t2 VALUES(1, 1, 'h'); 80b3c16b89Sdan INSERT INTO t2 VALUES(1, 2, 'g'); 81b3c16b89Sdan INSERT INTO t2 VALUES(2, 1, 'f'); 82b3c16b89Sdan INSERT INTO t2 VALUES(2, 2, 'e'); 83b3c16b89Sdan INSERT INTO t2 VALUES(3, 1, 'd'); 84b3c16b89Sdan INSERT INTO t2 VALUES(3, 2, 'c'); 85b3c16b89Sdan INSERT INTO t2 VALUES(4, 1, 'b'); 86b3c16b89Sdan INSERT INTO t2 VALUES(4, 2, 'a'); 87b3c16b89Sdan} 88b3c16b89Sdan 89ca3e3c3fSdando_execsql_test 2.1.1 { 90b3c16b89Sdan BEGIN; 91b3c16b89Sdan DELETE FROM t2 WHERE b=1 ORDER BY c LIMIT 2; 92b3c16b89Sdan SELECT c FROM t2 ORDER BY 1; 93b3c16b89Sdan ROLLBACK; 94b3c16b89Sdan} {a c e f g h} 95b3c16b89Sdan 96ca3e3c3fSdando_execsql_test 2.1.2 { 97b3c16b89Sdan BEGIN; 98b3c16b89Sdan UPDATE t2 SET c=NULL ORDER BY a, b DESC LIMIT 3 OFFSET 1; 99b3c16b89Sdan SELECT a, b, c FROM t2; 100b3c16b89Sdan ROLLBACK; 101b3c16b89Sdan} { 102b3c16b89Sdan 1 1 {} 103b3c16b89Sdan 1 2 g 104b3c16b89Sdan 2 1 {} 105b3c16b89Sdan 2 2 {} 106b3c16b89Sdan 3 1 d 107b3c16b89Sdan 3 2 c 108b3c16b89Sdan 4 1 b 109b3c16b89Sdan 4 2 a 110b3c16b89Sdan} 111b3c16b89Sdan 112ca3e3c3fSdando_execsql_test 2.2.0 { 113ca3e3c3fSdan DROP TABLE t2; 114ca3e3c3fSdan CREATE TABLE t2(a INTEGER PRIMARY KEY, b, c) WITHOUT ROWID; 115ca3e3c3fSdan INSERT INTO t2 VALUES(1, 1, 'h'); 116ca3e3c3fSdan INSERT INTO t2 VALUES(2, 2, 'g'); 117ca3e3c3fSdan INSERT INTO t2 VALUES(3, 1, 'f'); 118ca3e3c3fSdan INSERT INTO t2 VALUES(4, 2, 'e'); 119ca3e3c3fSdan INSERT INTO t2 VALUES(5, 1, 'd'); 120ca3e3c3fSdan INSERT INTO t2 VALUES(6, 2, 'c'); 121ca3e3c3fSdan INSERT INTO t2 VALUES(7, 1, 'b'); 122ca3e3c3fSdan INSERT INTO t2 VALUES(8, 2, 'a'); 123ca3e3c3fSdan} 124ca3e3c3fSdan 125ca3e3c3fSdando_execsql_test 2.2.1 { 126ca3e3c3fSdan BEGIN; 127ca3e3c3fSdan DELETE FROM t2 WHERE b=1 ORDER BY c LIMIT 2; 128ca3e3c3fSdan SELECT c FROM t2 ORDER BY 1; 129ca3e3c3fSdan ROLLBACK; 130ca3e3c3fSdan} {a c e f g h} 131ca3e3c3fSdan 132ca3e3c3fSdando_execsql_test 2.2.2 { 133ca3e3c3fSdan BEGIN; 134ca3e3c3fSdan UPDATE t2 SET c=NULL ORDER BY a DESC LIMIT 3 OFFSET 1; 135ca3e3c3fSdan SELECT a, b, c FROM t2; 136ca3e3c3fSdan ROLLBACK; 137ca3e3c3fSdan} { 138ca3e3c3fSdan 1 1 h 139ca3e3c3fSdan 2 2 g 140ca3e3c3fSdan 3 1 f 141ca3e3c3fSdan 4 2 e 142ca3e3c3fSdan 5 1 {} 143ca3e3c3fSdan 6 2 {} 144ca3e3c3fSdan 7 1 {} 145ca3e3c3fSdan 8 2 a 146ca3e3c3fSdan} 147ca3e3c3fSdan 14826caf5beSdan#------------------------------------------------------------------------- 14926caf5beSdan# Test using a virtual table 15026caf5beSdan# 15126caf5beSdanifcapable fts5 { 15226caf5beSdan do_execsql_test 3.0 { 15326caf5beSdan CREATE VIRTUAL TABLE ft USING fts5(x); 15426caf5beSdan INSERT INTO ft(rowid, x) VALUES(-45, 'a a'); 15526caf5beSdan INSERT INTO ft(rowid, x) VALUES(12, 'a b'); 15626caf5beSdan INSERT INTO ft(rowid, x) VALUES(444, 'a c'); 15726caf5beSdan INSERT INTO ft(rowid, x) VALUES(12300, 'a d'); 15826caf5beSdan INSERT INTO ft(rowid, x) VALUES(25400, 'a c'); 15926caf5beSdan INSERT INTO ft(rowid, x) VALUES(25401, 'a b'); 16026caf5beSdan INSERT INTO ft(rowid, x) VALUES(50000, 'a a'); 16126caf5beSdan } 16226caf5beSdan 16326caf5beSdan do_execsql_test 3.1.1 { 16426caf5beSdan BEGIN; 16526caf5beSdan DELETE FROM ft ORDER BY rowid LIMIT 3; 16626caf5beSdan SELECT x FROM ft; 16726caf5beSdan ROLLBACK; 16826caf5beSdan } {{a d} {a c} {a b} {a a}} 16926caf5beSdan 17026caf5beSdan do_execsql_test 3.1.2 { 17126caf5beSdan BEGIN; 17226caf5beSdan DELETE FROM ft WHERE ft MATCH 'a' ORDER BY rowid LIMIT 3; 17326caf5beSdan SELECT x FROM ft; 17426caf5beSdan ROLLBACK; 17526caf5beSdan } {{a d} {a c} {a b} {a a}} 17626caf5beSdan 17726caf5beSdan do_execsql_test 3.1.3 { 17826caf5beSdan BEGIN; 17926caf5beSdan DELETE FROM ft WHERE ft MATCH 'b' ORDER BY rowid ASC LIMIT 1 OFFSET 1; 18026caf5beSdan SELECT rowid FROM ft; 18126caf5beSdan ROLLBACK; 18226caf5beSdan } {-45 12 444 12300 25400 50000} 18326caf5beSdan 18426caf5beSdan do_execsql_test 3.2.1 { 18526caf5beSdan BEGIN; 18626caf5beSdan UPDATE ft SET x='hello' ORDER BY rowid LIMIT 2 OFFSET 2; 18726caf5beSdan SELECT x FROM ft; 18826caf5beSdan ROLLBACK; 18926caf5beSdan } {{a a} {a b} hello hello {a c} {a b} {a a}} 19026caf5beSdan 19126caf5beSdan do_execsql_test 3.2.2 { 19226caf5beSdan BEGIN; 19326caf5beSdan UPDATE ft SET x='hello' WHERE ft MATCH 'a' 19426caf5beSdan ORDER BY rowid DESC LIMIT 2 OFFSET 2; 19526caf5beSdan SELECT x FROM ft; 19626caf5beSdan ROLLBACK; 19726caf5beSdan } {{a a} {a b} {a c} hello hello {a b} {a a}} 19826caf5beSdan} ;# fts5 19926caf5beSdan 20026caf5beSdan#------------------------------------------------------------------------- 20126caf5beSdan# Test using INDEXED BY clauses. 20226caf5beSdan# 203ca3e3c3fSdando_execsql_test 4.0 { 204ca3e3c3fSdan CREATE TABLE x1(a INTEGER PRIMARY KEY, b, c, d); 20526caf5beSdan CREATE INDEX x1bc ON x1(b, c); 20626caf5beSdan INSERT INTO x1 VALUES(1,1,1,1); 20726caf5beSdan INSERT INTO x1 VALUES(2,1,2,2); 20826caf5beSdan INSERT INTO x1 VALUES(3,2,1,3); 20926caf5beSdan INSERT INTO x1 VALUES(4,2,2,3); 21026caf5beSdan INSERT INTO x1 VALUES(5,3,1,2); 21126caf5beSdan INSERT INTO x1 VALUES(6,3,2,1); 21226caf5beSdan} 21326caf5beSdan 214ca3e3c3fSdando_execsql_test 4.1 { 21526caf5beSdan BEGIN; 21626caf5beSdan DELETE FROM x1 ORDER BY a LIMIT 2; 21726caf5beSdan SELECT a FROM x1; 21826caf5beSdan ROLLBACK; 21926caf5beSdan} {3 4 5 6} 22026caf5beSdan 221*51da8dafSdrh# 2020-06-03: Query planner improved so that a solution is possible. 222*51da8dafSdrh# 223*51da8dafSdrh#do_catchsql_test 4.2 { 224*51da8dafSdrh# DELETE FROM x1 INDEXED BY x1bc WHERE d=3 LIMIT 1; 225*51da8dafSdrh#} {1 {no query solution}} 22626caf5beSdan 227ca3e3c3fSdando_execsql_test 4.3 { 228ca3e3c3fSdan DELETE FROM x1 INDEXED BY x1bc WHERE b=3 LIMIT 1; 229ca3e3c3fSdan SELECT a FROM x1; 230ca3e3c3fSdan} {1 2 3 4 6} 23126caf5beSdan 232*51da8dafSdrh# 2020-06-03: Query planner improved so that a solution is possible. 233*51da8dafSdrh# 234*51da8dafSdrh#do_catchsql_test 4.4 { 235*51da8dafSdrh# UPDATE x1 INDEXED BY x1bc SET d=5 WHERE d=3 LIMIT 1; 236*51da8dafSdrh#} {1 {no query solution}} 237ca3e3c3fSdan 238ca3e3c3fSdando_execsql_test 4.5 { 239ca3e3c3fSdan UPDATE x1 INDEXED BY x1bc SET d=5 WHERE b=2 LIMIT 1; 240ca3e3c3fSdan SELECT a, d FROM x1; 241ca3e3c3fSdan} {1 1 2 2 3 5 4 3 6 1} 24226caf5beSdan 24326caf5beSdan#------------------------------------------------------------------------- 24426caf5beSdan# Test using object names that require quoting. 24526caf5beSdan# 246dc32b448Sdando_execsql_test 5.0 { 247dc32b448Sdan CREATE TABLE "x y"("a b" PRIMARY KEY, "c d") WITHOUT ROWID; 248dc32b448Sdan CREATE INDEX xycd ON "x y"("c d"); 24926caf5beSdan 250dc32b448Sdan INSERT INTO "x y" VALUES('a', 'a'); 251dc32b448Sdan INSERT INTO "x y" VALUES('b', 'b'); 252dc32b448Sdan INSERT INTO "x y" VALUES('c', 'c'); 253dc32b448Sdan INSERT INTO "x y" VALUES('d', 'd'); 254dc32b448Sdan INSERT INTO "x y" VALUES('e', 'a'); 255dc32b448Sdan INSERT INTO "x y" VALUES('f', 'b'); 256dc32b448Sdan INSERT INTO "x y" VALUES('g', 'c'); 257dc32b448Sdan INSERT INTO "x y" VALUES('h', 'd'); 258dc32b448Sdan} 259dc32b448Sdan 260dc32b448Sdando_execsql_test 5.1 { 261dc32b448Sdan BEGIN; 262dc32b448Sdan DELETE FROM "x y" WHERE "c d"!='e' ORDER BY "c d" LIMIT 2 OFFSET 2; 263dc32b448Sdan SELECT * FROM "x y" ORDER BY 1; 264dc32b448Sdan ROLLBACK; 265dc32b448Sdan} { 266dc32b448Sdan a a c c d d e a g c h d 267dc32b448Sdan} 268dc32b448Sdan 269dc32b448Sdando_execsql_test 5.2 { 270dc32b448Sdan BEGIN; 271dc32b448Sdan UPDATE "x y" SET "c d"='e' WHERE "c d"!='e' ORDER BY "c d" LIMIT 2 OFFSET 2; 272dc32b448Sdan SELECT * FROM "x y" ORDER BY 1; 273dc32b448Sdan ROLLBACK; 274dc32b448Sdan} { 275dc32b448Sdan a a b e c c d d e a f e g c h d 276dc32b448Sdan} 277dc32b448Sdan 278dc32b448Sdanproc log {args} { lappend ::log {*}$args } 279dc32b448Sdandb func log log 280dc32b448Sdando_execsql_test 5.3 { 281dc32b448Sdan CREATE VIEW "v w" AS SELECT * FROM "x y"; 282dc32b448Sdan CREATE TRIGGER tr1 INSTEAD OF DELETE ON "v w" BEGIN 283dc32b448Sdan SELECT log(old."a b", old."c d"); 284dc32b448Sdan END; 285dc32b448Sdan CREATE TRIGGER tr2 INSTEAD OF UPDATE ON "v w" BEGIN 286dc32b448Sdan SELECT log(new."a b", new."c d"); 287dc32b448Sdan END; 288dc32b448Sdan} 289dc32b448Sdan 290dc32b448Sdando_test 5.4 { 291dc32b448Sdan set ::log {} 292dc32b448Sdan execsql { DELETE FROM "v w" ORDER BY "a b" LIMIT 3 } 293dc32b448Sdan set ::log 294dc32b448Sdan} {a a b b c c} 295dc32b448Sdan 296dc32b448Sdando_test 5.5 { 297dc32b448Sdan set ::log {} 298dc32b448Sdan execsql { UPDATE "v w" SET "a b" = "a b" || 'x' ORDER BY "a b" LIMIT 5; } 299dc32b448Sdan set ::log 300dc32b448Sdan} {ax a bx b cx c dx d ex a} 301b3c16b89Sdan 302b3c16b89Sdan 303b3c16b89Sdanfinish_test 304