xref: /sqlite-3.40.0/test/fuzz.test (revision de58ddb7)
1# 2007 May 10
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 generating semi-random strings of SQL
13# (a.k.a. "fuzz") and sending it into the parser to try to
14# generate errors.
15#
16# The tests in this file are really about testing fuzzily generated
17# SQL parse-trees. The majority of the fuzzily generated SQL is
18# valid as far as the parser is concerned.
19#
20# The most complicated trees are for SELECT statements.
21#
22# $Id: fuzz.test,v 1.16 2009/01/05 22:30:39 drh Exp $
23
24set testdir [file dirname $argv0]
25source $testdir/tester.tcl
26
27set ::REPEATS 5000
28
29# If running quick.test, don't do so many iterations.
30if {[info exists ::ISQUICK]} {
31  if {$::ISQUICK} { set ::REPEATS 20 }
32}
33
34source $testdir/fuzz_common.tcl
35expr srand(0)
36
37#----------------------------------------------------------------
38# These tests caused errors that were first caught by the tests
39# in this file. They are still here.
40do_test fuzz-1.1 {
41  execsql {
42    SELECT 'abc' LIKE X'ABCD';
43  }
44} {0}
45do_test fuzz-1.2 {
46  execsql {
47    SELECT 'abc' LIKE zeroblob(10);
48  }
49} {0}
50do_test fuzz-1.3 {
51  execsql {
52    SELECT zeroblob(10) LIKE 'abc';
53  }
54} {0}
55do_test fuzz-1.4 {
56  execsql {
57    SELECT (- -21) % NOT (456 LIKE zeroblob(10));
58  }
59} {0}
60do_test fuzz-1.5 {
61  execsql {
62    SELECT (SELECT (
63        SELECT (SELECT -2147483648) FROM (SELECT 1) ORDER BY 1
64    ))
65  }
66} {-2147483648}
67do_test fuzz-1.6 {
68  execsql {
69    SELECT 'abc', zeroblob(1) FROM (SELECT 1) ORDER BY 1
70  }
71} [execsql {SELECT 'abc', zeroblob(1)}]
72
73do_test fuzz-1.7 {
74  execsql {
75    SELECT ( SELECT zeroblob(1000) FROM (
76      SELECT * FROM (SELECT 'first') ORDER BY NOT 'in')
77    )
78  }
79} [execsql {SELECT zeroblob(1000)}]
80
81do_test fuzz-1.8 {
82  # Problems with opcode OP_ToText (did not account for MEM_Zero).
83  # Also MemExpandBlob() was marking expanded blobs as nul-terminated.
84  # They are not.
85  execsql {
86    SELECT CAST(zeroblob(1000) AS text);
87  }
88} {{}}
89
90do_test fuzz-1.9 {
91  # This was causing a NULL pointer dereference of Expr.pList.
92  execsql {
93    SELECT 1 FROM (SELECT * FROM sqlite_master WHERE random())
94  }
95} {}
96
97do_test fuzz-1.10 {
98  # Bug in calculation of Parse.ckOffset causing an assert()
99  # to fail. Probably harmless.
100  execsql {
101    SELECT coalesce(1, substr( 1, 2, length('in' IN (SELECT 1))))
102  }
103} {1}
104
105do_test fuzz-1.11 {
106  # The literals (A, B, C, D) are not important, they are just used
107  # to make the EXPLAIN output easier to read.
108  #
109  # The problem here is that the EXISTS(...) expression leaves an
110  # extra value on the VDBE stack. This is confusing the parent and
111  # leads to an assert() failure when OP_Insert encounters an integer
112  # when it expects a record blob.
113  #
114  # Update: Any query with (LIMIT 0) was leaking stack.
115  #
116  execsql {
117    SELECT 'A' FROM (SELECT 'B') ORDER BY EXISTS (
118      SELECT 'C' FROM (SELECT 'D' LIMIT 0)
119    )
120  }
121} {A}
122
123do_test fuzz-1.12.1 {
124  # Create a table with a single row.
125  execsql {
126    CREATE TABLE abc(b);
127    INSERT INTO abc VALUES('ABCDE');
128  }
129
130  # The following query was crashing. The later subquery (in the FROM)
131  # clause was flattened into the parent, but the code was not repairng
132  # the "b" reference in the other sub-query. When the query was executed,
133  # that "b" refered to a non-existant vdbe table-cursor.
134  #
135  execsql {
136    SELECT 1 IN ( SELECT b UNION SELECT 1 ) FROM (SELECT b FROM abc);
137  }
138} {1}
139do_test fuzz-1.12.2 {
140  # Clean up after the previous query.
141  execsql {
142    DROP TABLE abc;
143  }
144} {}
145
146
147do_test fuzz-1.13 {
148  # The problem here was that when there were more expressions in
149  # the ORDER BY list than the result-set list. The temporary b-tree
150  # used for sorting was being misconfigured in this case.
151  #
152  execsql {
153    SELECT 'abcd' UNION SELECT 'efgh' ORDER BY 1 ASC, 1 ASC;
154  }
155} {abcd efgh}
156
157do_test fuzz-1.14.1 {
158  execsql {
159    CREATE TABLE abc(a, b, c);
160    INSERT INTO abc VALUES(123, 456, 789);
161  }
162
163  # The [a] reference in the sub-select was causing a problem. Because
164  # the internal walkSelectExpr() function was not considering compound
165  # SELECT operators.
166  execsql {
167    SELECT 1 FROM abc
168    GROUP BY c HAVING EXISTS (SELECT a UNION SELECT 123);
169  }
170} {1}
171do_test fuzz-1.14.2 {
172  execsql {
173    DROP TABLE abc;
174  }
175} {}
176
177# Making sure previously discovered errors have been fixed.
178#
179do_test fuzz-1.15 {
180  execsql {
181    SELECT hex(CAST(zeroblob(1000) AS integer))
182  }
183} {30}
184
185do_test fuzz-1.16.1 {
186  execsql {
187    CREATE TABLE abc(a, b, c);
188    CREATE TABLE def(a, b, c);
189    CREATE TABLE ghi(a, b, c);
190  }
191} {}
192do_test fuzz-1.16.2 {
193breakpoint
194  catchsql {
195    SELECT DISTINCT EXISTS(
196       SELECT 1
197       FROM (
198         SELECT C FROM (SELECT 1)
199       )
200       WHERE (SELECT c)
201    )
202    FROM abc
203  }
204} {0 {}}
205do_test fuzz-1.16.3 {
206  catchsql {
207    SELECT DISTINCT substr(-456 ISNULL,zeroblob(1000), EXISTS(
208         SELECT DISTINCT EXISTS(
209           SELECT DISTINCT b FROM abc
210           ORDER BY EXISTS (
211             SELECT DISTINCT 2147483647 UNION ALL SELECT -2147483648
212           ) ASC
213         )
214         FROM (
215           SELECT c, c FROM (
216             SELECT 456, 'injection' ORDER BY 56.1 ASC, -56.1 DESC
217           )
218         )
219         GROUP BY (SELECT ALL (SELECT DISTINCT 'hardware'))
220         HAVING (
221           SELECT DISTINCT c
222           FROM (
223             SELECT ALL -2147483648, 'experiments'
224             ORDER BY -56.1 ASC, -56.1 DESC
225           )
226           GROUP BY (SELECT DISTINCT 456) IN
227                   (SELECT DISTINCT 'injection') NOT IN (SELECT ALL -456)
228           HAVING EXISTS (
229             SELECT ALL 'injection'
230           )
231         )
232         UNION ALL
233         SELECT a IN (
234           SELECT -2147483647
235           UNION ALL
236           SELECT ALL 'injection'
237         )
238         FROM sqlite_master
239       ) -- end EXISTS
240    ) /* end SUBSTR() */, c NOTNULL ISNULL
241    FROM abc
242    ORDER BY CAST(-56.1 AS blob) ASC
243  }
244} {0 {}}
245do_test fuzz-1.16.4 {
246  execsql {
247    DROP TABLE abc; DROP TABLE def; DROP TABLE ghi;
248  }
249} {}
250
251do_test fuzz-1.17 {
252  catchsql {
253    SELECT 'hardware', 56.1 NOTNULL, random()&0
254    FROM (
255       SELECT ALL lower(~ EXISTS (
256           SELECT 1 NOT IN (SELECT ALL 1)
257       )), CAST(456 AS integer), -2147483647
258       FROM (
259         SELECT DISTINCT -456, CAST(1 AS integer) ISNULL
260         FROM (SELECT ALL 2147483647, typeof(2147483649))
261       )
262    )
263    GROUP BY CAST(CAST('experiments' AS blob) AS blob)
264    HAVING random()
265  }
266} {0 {hardware 1 0}}
267
268#----------------------------------------------------------------
269# Test some fuzzily generated expressions.
270#
271do_fuzzy_test fuzz-2 -template  { SELECT [Expr] }
272
273do_test fuzz-3.1 {
274  execsql {
275    CREATE TABLE abc(a, b, c);
276    CREATE TABLE def(a, b, c);
277    CREATE TABLE ghi(a, b, c);
278  }
279} {}
280set ::TableList  [list abc def ghi]
281
282#----------------------------------------------------------------
283# Test some fuzzily generated SELECT statements.
284#
285do_fuzzy_test fuzz-3.2 -template  {[Select]}
286
287#----------------------------------------------------------------
288# Insert a small amount of data into the database and then run
289# some more generated SELECT statements.
290#
291do_test fuzz-4.1 {
292  execsql {
293    INSERT INTO abc VALUES(1, 2, 3);
294    INSERT INTO abc VALUES(4, 5, 6);
295    INSERT INTO abc VALUES(7, 8, 9);
296    INSERT INTO def VALUES(1, 2, 3);
297    INSERT INTO def VALUES(4, 5, 6);
298    INSERT INTO def VALUES(7, 8, 9);
299    INSERT INTO ghi VALUES(1, 2, 3);
300    INSERT INTO ghi VALUES(4, 5, 6);
301    INSERT INTO ghi VALUES(7, 8, 9);
302    CREATE INDEX abc_i ON abc(a, b, c);
303    CREATE INDEX def_i ON def(c, a, b);
304    CREATE INDEX ghi_i ON ghi(b, c, a);
305  }
306} {}
307do_fuzzy_test fuzz-4.2 -template {[Select]}
308
309#----------------------------------------------------------------
310# Test some fuzzy INSERT statements:
311#
312do_test         fuzz-5.1 {execsql BEGIN} {}
313do_fuzzy_test   fuzz-5.2 -template  {[Insert]} -errorlist table
314integrity_check fuzz-5.2.integrity
315do_test         fuzz-5.3 {execsql COMMIT} {}
316integrity_check fuzz-5.4.integrity
317
318#----------------------------------------------------------------
319# Now that there is data in the database, run some more SELECT
320# statements
321#
322set ::ColumnList [list a b c]
323set E {{no such col} {ambiguous column name}}
324do_fuzzy_test fuzz-6.1 -template {[Select]} -errorlist $E
325
326#----------------------------------------------------------------
327# Run some SELECTs, INSERTs, UPDATEs and DELETEs in a transaction.
328#
329set E {{no such col} {ambiguous column name} {table}}
330do_test         fuzz-7.1 {execsql BEGIN} {}
331do_fuzzy_test   fuzz-7.2 -template {[Statement]} -errorlist $E
332integrity_check fuzz-7.3.integrity
333do_test         fuzz-7.4 {execsql COMMIT} {}
334integrity_check fuzz-7.5.integrity
335
336#----------------------------------------------------------------
337# Many CREATE and DROP TABLE statements:
338#
339set E [list table duplicate {no such col} {ambiguous column name} {use DROP}]
340do_fuzzy_test fuzz-8.1 -template {[CreateOrDropTableOrView]} -errorlist $E
341
342close $::log
343finish_test
344