xref: /sqlite-3.40.0/test/wherelimit2.test (revision 51da8daf)
1# 2008 October 6
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# This file implements regression tests for SQLite library.  The
12# focus of this file is testing the LIMIT ... OFFSET ... clause
13#  of UPDATE and DELETE statements.
14#
15
16set testdir [file dirname $argv0]
17source $testdir/tester.tcl
18set testprefix wherelimit2
19
20ifcapable !update_delete_limit {
21  finish_test
22  return
23}
24
25#-------------------------------------------------------------------------
26# Test with views and INSTEAD OF triggers.
27#
28do_execsql_test 1.0 {
29  CREATE TABLE t1(a, b);
30  INSERT INTO t1 VALUES(1, 'f');
31  INSERT INTO t1 VALUES(2, 'e');
32  INSERT INTO t1 VALUES(3, 'd');
33  INSERT INTO t1 VALUES(4, 'c');
34  INSERT INTO t1 VALUES(5, 'b');
35  INSERT INTO t1 VALUES(6, 'a');
36
37  CREATE VIEW v1 AS SELECT a,b FROM t1;
38  CREATE TABLE log(op, a);
39
40  CREATE TRIGGER v1del INSTEAD OF DELETE ON v1 BEGIN
41    INSERT INTO log VALUES('delete', old.a);
42  END;
43
44  CREATE TRIGGER v1upd INSTEAD OF UPDATE ON v1 BEGIN
45    INSERT INTO log VALUES('update', old.a);
46  END;
47}
48
49do_execsql_test 1.1 {
50  DELETE FROM v1 ORDER BY a LIMIT 3;
51  SELECT * FROM log; DELETE FROM log;
52} {
53  delete 1 delete 2 delete 3
54}
55do_execsql_test 1.2 {
56  DELETE FROM v1 ORDER BY b LIMIT 3;
57  SELECT * FROM log; DELETE FROM log;
58} {
59  delete 6 delete 5 delete 4
60}
61do_execsql_test 1.3 {
62  UPDATE v1 SET b = 555 ORDER BY a LIMIT 3;
63  SELECT * FROM log; DELETE FROM log;
64} {
65  update 1 update 2 update 3
66}
67do_execsql_test 1.4 {
68  UPDATE v1 SET b = 555 ORDER BY b LIMIT 3;
69  SELECT * FROM log; DELETE FROM log;
70} {
71  update 6 update 5 update 4
72}
73
74#-------------------------------------------------------------------------
75# Simple test using WITHOUT ROWID table.
76#
77do_execsql_test 2.1.0 {
78  CREATE TABLE t2(a, b, c, PRIMARY KEY(a, b)) WITHOUT ROWID;
79  INSERT INTO t2 VALUES(1, 1, 'h');
80  INSERT INTO t2 VALUES(1, 2, 'g');
81  INSERT INTO t2 VALUES(2, 1, 'f');
82  INSERT INTO t2 VALUES(2, 2, 'e');
83  INSERT INTO t2 VALUES(3, 1, 'd');
84  INSERT INTO t2 VALUES(3, 2, 'c');
85  INSERT INTO t2 VALUES(4, 1, 'b');
86  INSERT INTO t2 VALUES(4, 2, 'a');
87}
88
89do_execsql_test 2.1.1 {
90  BEGIN;
91    DELETE FROM t2 WHERE b=1 ORDER BY c LIMIT 2;
92    SELECT c FROM t2 ORDER BY 1;
93  ROLLBACK;
94} {a c e f g h}
95
96do_execsql_test 2.1.2 {
97  BEGIN;
98    UPDATE t2 SET c=NULL ORDER BY a, b DESC LIMIT 3 OFFSET 1;
99    SELECT a, b, c FROM t2;
100  ROLLBACK;
101} {
102  1 1 {}
103  1 2 g
104  2 1 {}
105  2 2 {}
106  3 1 d
107  3 2 c
108  4 1 b
109  4 2 a
110}
111
112do_execsql_test 2.2.0 {
113  DROP TABLE t2;
114  CREATE TABLE t2(a INTEGER PRIMARY KEY, b, c) WITHOUT ROWID;
115  INSERT INTO t2 VALUES(1, 1, 'h');
116  INSERT INTO t2 VALUES(2, 2, 'g');
117  INSERT INTO t2 VALUES(3, 1, 'f');
118  INSERT INTO t2 VALUES(4, 2, 'e');
119  INSERT INTO t2 VALUES(5, 1, 'd');
120  INSERT INTO t2 VALUES(6, 2, 'c');
121  INSERT INTO t2 VALUES(7, 1, 'b');
122  INSERT INTO t2 VALUES(8, 2, 'a');
123}
124
125do_execsql_test 2.2.1 {
126  BEGIN;
127    DELETE FROM t2 WHERE b=1 ORDER BY c LIMIT 2;
128    SELECT c FROM t2 ORDER BY 1;
129  ROLLBACK;
130} {a c e f g h}
131
132do_execsql_test 2.2.2 {
133  BEGIN;
134    UPDATE t2 SET c=NULL ORDER BY a DESC LIMIT 3 OFFSET 1;
135    SELECT a, b, c FROM t2;
136  ROLLBACK;
137} {
138  1 1 h
139  2 2 g
140  3 1 f
141  4 2 e
142  5 1 {}
143  6 2 {}
144  7 1 {}
145  8 2 a
146}
147
148#-------------------------------------------------------------------------
149# Test using a virtual table
150#
151ifcapable fts5 {
152  do_execsql_test 3.0 {
153    CREATE VIRTUAL TABLE ft USING fts5(x);
154    INSERT INTO ft(rowid, x) VALUES(-45,   'a a');
155    INSERT INTO ft(rowid, x) VALUES(12,    'a b');
156    INSERT INTO ft(rowid, x) VALUES(444,   'a c');
157    INSERT INTO ft(rowid, x) VALUES(12300, 'a d');
158    INSERT INTO ft(rowid, x) VALUES(25400, 'a c');
159    INSERT INTO ft(rowid, x) VALUES(25401, 'a b');
160    INSERT INTO ft(rowid, x) VALUES(50000, 'a a');
161  }
162
163  do_execsql_test 3.1.1 {
164    BEGIN;
165      DELETE FROM ft ORDER BY rowid LIMIT 3;
166      SELECT x FROM ft;
167    ROLLBACK;
168  } {{a d} {a c} {a b} {a a}}
169
170  do_execsql_test 3.1.2 {
171    BEGIN;
172      DELETE FROM ft WHERE ft MATCH 'a' ORDER BY rowid LIMIT 3;
173      SELECT x FROM ft;
174    ROLLBACK;
175  } {{a d} {a c} {a b} {a a}}
176
177  do_execsql_test 3.1.3 {
178    BEGIN;
179      DELETE FROM ft WHERE ft MATCH 'b' ORDER BY rowid ASC LIMIT 1 OFFSET 1;
180      SELECT rowid FROM ft;
181    ROLLBACK;
182  } {-45 12 444 12300 25400 50000}
183
184  do_execsql_test 3.2.1 {
185    BEGIN;
186      UPDATE ft SET x='hello' ORDER BY rowid LIMIT 2 OFFSET 2;
187      SELECT x FROM ft;
188    ROLLBACK;
189  } {{a a} {a b} hello hello {a c} {a b} {a a}}
190
191  do_execsql_test 3.2.2 {
192    BEGIN;
193      UPDATE ft SET x='hello' WHERE ft MATCH 'a'
194          ORDER BY rowid DESC LIMIT 2 OFFSET 2;
195      SELECT x FROM ft;
196    ROLLBACK;
197  } {{a a} {a b} {a c} hello hello {a b} {a a}}
198} ;# fts5
199
200#-------------------------------------------------------------------------
201# Test using INDEXED BY clauses.
202#
203do_execsql_test 4.0 {
204  CREATE TABLE x1(a INTEGER PRIMARY KEY, b, c, d);
205  CREATE INDEX x1bc ON x1(b, c);
206  INSERT INTO x1 VALUES(1,1,1,1);
207  INSERT INTO x1 VALUES(2,1,2,2);
208  INSERT INTO x1 VALUES(3,2,1,3);
209  INSERT INTO x1 VALUES(4,2,2,3);
210  INSERT INTO x1 VALUES(5,3,1,2);
211  INSERT INTO x1 VALUES(6,3,2,1);
212}
213
214do_execsql_test 4.1 {
215  BEGIN;
216    DELETE FROM x1 ORDER BY a LIMIT 2;
217    SELECT a FROM x1;
218  ROLLBACK;
219} {3 4 5 6}
220
221# 2020-06-03: Query planner improved so that a solution is possible.
222#
223#do_catchsql_test 4.2 {
224#  DELETE FROM x1 INDEXED BY x1bc WHERE d=3 LIMIT 1;
225#} {1 {no query solution}}
226
227do_execsql_test 4.3 {
228  DELETE FROM x1 INDEXED BY x1bc WHERE b=3 LIMIT 1;
229  SELECT a FROM x1;
230} {1 2 3 4 6}
231
232# 2020-06-03: Query planner improved so that a solution is possible.
233#
234#do_catchsql_test 4.4 {
235#  UPDATE x1 INDEXED BY x1bc SET d=5 WHERE d=3 LIMIT 1;
236#} {1 {no query solution}}
237
238do_execsql_test 4.5 {
239  UPDATE x1 INDEXED BY x1bc SET d=5 WHERE b=2 LIMIT 1;
240  SELECT a, d FROM x1;
241} {1 1 2 2 3 5 4 3 6 1}
242
243#-------------------------------------------------------------------------
244# Test using object names that require quoting.
245#
246do_execsql_test 5.0 {
247  CREATE TABLE "x y"("a b" PRIMARY KEY, "c d") WITHOUT ROWID;
248  CREATE INDEX xycd ON "x y"("c d");
249
250  INSERT INTO "x y" VALUES('a', 'a');
251  INSERT INTO "x y" VALUES('b', 'b');
252  INSERT INTO "x y" VALUES('c', 'c');
253  INSERT INTO "x y" VALUES('d', 'd');
254  INSERT INTO "x y" VALUES('e', 'a');
255  INSERT INTO "x y" VALUES('f', 'b');
256  INSERT INTO "x y" VALUES('g', 'c');
257  INSERT INTO "x y" VALUES('h', 'd');
258}
259
260do_execsql_test 5.1 {
261  BEGIN;
262    DELETE FROM "x y" WHERE "c d"!='e' ORDER BY "c d" LIMIT 2 OFFSET 2;
263    SELECT * FROM "x y" ORDER BY 1;
264  ROLLBACK;
265} {
266  a a c c d d e a g c h d
267}
268
269do_execsql_test 5.2 {
270  BEGIN;
271    UPDATE "x y" SET "c d"='e' WHERE "c d"!='e' ORDER BY "c d" LIMIT 2 OFFSET 2;
272    SELECT * FROM "x y" ORDER BY 1;
273  ROLLBACK;
274} {
275  a a b e c c d d e a f e g c h d
276}
277
278proc log {args} { lappend ::log {*}$args }
279db func log log
280do_execsql_test 5.3 {
281  CREATE VIEW "v w" AS SELECT * FROM "x y";
282  CREATE TRIGGER tr1 INSTEAD OF DELETE ON "v w" BEGIN
283    SELECT log(old."a b", old."c d");
284  END;
285  CREATE TRIGGER tr2 INSTEAD OF UPDATE ON "v w" BEGIN
286    SELECT log(new."a b", new."c d");
287  END;
288}
289
290do_test 5.4 {
291  set ::log {}
292  execsql { DELETE FROM "v w" ORDER BY "a b" LIMIT 3 }
293  set ::log
294} {a a b b c c}
295
296do_test 5.5 {
297  set ::log {}
298  execsql { UPDATE "v w" SET "a b" = "a b" || 'x' ORDER BY "a b" LIMIT 5; }
299  set ::log
300} {ax a bx b cx c dx d ex a}
301
302
303finish_test
304