blob: b4e27b2faf93f4d55d16baa1258fe2868af84d02 [file] [log] [blame]
drhdb83f822007-05-11 00:20:08 +00001# 2007 May 10
danielk1977def0fec2007-05-10 15:37:52 +00002#
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
drhdb83f822007-05-11 00:20:08 +000012# 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 generate
14# errors.
danielk1977def0fec2007-05-10 15:37:52 +000015#
danielk1977bcfc4bc2007-05-11 10:10:33 +000016# $Id: fuzz.test,v 1.6 2007/05/11 10:10:33 danielk1977 Exp $
danielk1977def0fec2007-05-10 15:37:52 +000017
18set testdir [file dirname $argv0]
19source $testdir/tester.tcl
20
21proc fuzz {TemplateList} {
22 set n [llength $TemplateList]
23 set i [expr {int(rand()*$n)}]
danielk1977bcfc4bc2007-05-11 10:10:33 +000024 return [uplevel 1 subst -novar [list [lindex $TemplateList $i]]]
danielk1977def0fec2007-05-10 15:37:52 +000025}
26
danielk1977bcfc4bc2007-05-11 10:10:33 +000027# Fuzzy generation primitives:
28#
29# Literal
30# UnaryOp
31# BinaryOp
32# Expr
33# Table
34# Select
35# Insert
36#
37
danielk1977f75232f2007-05-10 17:32:48 +000038# Returns a string representing an SQL literal.
39#
40proc Literal {} {
danielk1977def0fec2007-05-10 15:37:52 +000041 set TemplateList {
42 456 0 -456 1 -1
43 2147483648 2147483647 2147483649 -2147483647 -2147483648 -2147483649
44 'The' 'first' 'experiments' 'in' 'hardware' 'fault' 'injection'
45 zeroblob(1000)
46 NULL
47 56.1 -56.1
48 123456789.1234567899
49 }
50 fuzz $TemplateList
51}
52
danielk1977bcfc4bc2007-05-11 10:10:33 +000053# Returns a string containing an SQL unary operator (e.g. "+" or "NOT").
54#
danielk1977def0fec2007-05-10 15:37:52 +000055proc UnaryOp {} {
danielk1977bcfc4bc2007-05-11 10:10:33 +000056 set TemplateList {+ - NOT ~}
danielk1977def0fec2007-05-10 15:37:52 +000057 fuzz $TemplateList
58}
59
danielk1977bcfc4bc2007-05-11 10:10:33 +000060# Returns a string containing an SQL binary operator (e.g. "*" or "/").
61#
danielk1977def0fec2007-05-10 15:37:52 +000062proc BinaryOp {} {
danielk1977bcfc4bc2007-05-11 10:10:33 +000063 set TemplateList {
64 || * / % + - << >> & | < <= > >= = == != <> AND OR
65 LIKE GLOB {NOT LIKE}
66 }
danielk1977def0fec2007-05-10 15:37:52 +000067 fuzz $TemplateList
68}
69
danielk1977bcfc4bc2007-05-11 10:10:33 +000070# Return the complete text of an SQL expression.
71#
danielk1977def0fec2007-05-10 15:37:52 +000072set ::ExprDepth 0
danielk1977bcfc4bc2007-05-11 10:10:33 +000073proc Expr { {c {}} } {
danielk1977def0fec2007-05-10 15:37:52 +000074 incr ::ExprDepth
75
danielk1977bcfc4bc2007-05-11 10:10:33 +000076 set TemplateList [concat $c {[Literal]}]
77 if {$::ExprDepth < 25} {
danielk1977def0fec2007-05-10 15:37:52 +000078 lappend TemplateList \
danielk1977bcfc4bc2007-05-11 10:10:33 +000079 {[Expr $c] [BinaryOp] [Expr $c]} \
80 {[UnaryOp] [Expr $c]} \
81 {[Expr $c] ISNULL} \
82 {[Expr $c] NOTNULL} \
83 {CAST([Expr $c] AS blob)} \
84 {CAST([Expr $c] AS text)} \
85 {CAST([Expr $c] AS integer)} \
86 {CAST([Expr $c] AS real)} \
87 {CASE WHEN [Expr $c] THEN [Expr $c] ELSE [Expr $c] END} \
88 {[Literal]} {[Literal]} {[Literal]}
danielk1977def0fec2007-05-10 15:37:52 +000089 }
90 if {$::SelectDepth < 10} {
danielk1977bcfc4bc2007-05-11 10:10:33 +000091 lappend TemplateList \
92 {([Select 1])} \
93 {[Expr $c] IN ([Select 1])} \
94 {[Expr $c] NOT IN ([Select 1])} \
95 {EXISTS ([Select 1])} \
danielk1977def0fec2007-05-10 15:37:52 +000096 }
97 set res [fuzz $TemplateList]
98 incr ::ExprDepth -1
99 return $res
100}
101
danielk1977bcfc4bc2007-05-11 10:10:33 +0000102# Return a valid table name.
103#
danielk1977f75232f2007-05-10 17:32:48 +0000104set ::TableList [list]
105proc Table {} {
106 set TemplateList [concat sqlite_master $::TableList]
107 fuzz $TemplateList
108}
109
danielk1977bcfc4bc2007-05-11 10:10:33 +0000110# Return a SELECT statement.
111#
danielk1977def0fec2007-05-10 15:37:52 +0000112set ::SelectDepth 0
danielk1977f75232f2007-05-10 17:32:48 +0000113proc Select {{isExpr 0}} {
danielk1977def0fec2007-05-10 15:37:52 +0000114 incr ::SelectDepth
115 set TemplateList {
116 {SELECT [Expr]}
danielk1977bcfc4bc2007-05-11 10:10:33 +0000117 {SELECT [Literal]}
danielk1977def0fec2007-05-10 15:37:52 +0000118 }
danielk1977f75232f2007-05-10 17:32:48 +0000119 if {$::SelectDepth < 5} {
120 lappend TemplateList \
121 {SELECT [Expr] FROM ([Select])} \
danielk1977bcfc4bc2007-05-11 10:10:33 +0000122 {SELECT [Expr] FROM [Table]} \
danielk1977f75232f2007-05-10 17:32:48 +0000123
124 if {0 == $isExpr} {
125 lappend TemplateList \
126 {SELECT [Expr], [Expr] FROM ([Select]) ORDER BY [Expr]} \
127 {SELECT * FROM ([Select]) ORDER BY [Expr]} \
danielk1977bcfc4bc2007-05-11 10:10:33 +0000128 {SELECT * FROM [Table]} \
129 {SELECT * FROM [Table] WHERE [Expr]} \
danielk1977f75232f2007-05-10 17:32:48 +0000130 }
131 }
danielk1977def0fec2007-05-10 15:37:52 +0000132 set res [fuzz $TemplateList]
133 incr ::SelectDepth -1
134 set res
135}
136
danielk1977bcfc4bc2007-05-11 10:10:33 +0000137# Generate and return a fuzzy INSERT statement.
138#
139proc Insert {} {
140 set TemplateList {
141 {INSERT INTO [Table] VALUES([Expr], [Expr], [Expr]);}
142 {INSERT INTO [Table] VALUES([Expr], [Expr], [Expr], [Expr]);}
143 {INSERT INTO [Table] VALUES([Expr], [Expr]);}
144 }
145 fuzz $TemplateList
146}
147
danielk1977f75232f2007-05-10 17:32:48 +0000148########################################################################
149
danielk1977bcfc4bc2007-05-11 10:10:33 +0000150set ::log [open fuzzy.log w]
151
152#
153# Usage: do_fuzzy_test <testname> ?<options>?
154#
155# -template
156# -errorlist
157#
158proc do_fuzzy_test {testname args} {
159 set ::fuzzyopts(-errorlist) [list]
160 array set ::fuzzyopts $args
161 lappend ::fuzzyopts(-errorlist) {parser stack overflow} {ORDER BY column}
162
163 for {set ii 0} {$ii < 2000} {incr ii} {
164 do_test ${testname}.$ii {
165 set ::sql [subst $::fuzzyopts(-template)]
166 puts $::log $::sql
167 flush $::log
168 set rc [catch {execsql $::sql} msg]
169 set e 1
170 if {$rc} {
171 set e 0
172 foreach error $::fuzzyopts(-errorlist) {
173 if {0 == [string first $error $msg]} {
174 set e 1
175 break
176 }
177 }
178 }
179 if {$e == 0} {
180 puts ""
181 puts $::sql
182 puts $msg
183 }
184 set e
185 } {1}
186 }
187}
188
danielk1977f75232f2007-05-10 17:32:48 +0000189#----------------------------------------------------------------
190# These tests caused errors that were first caught by the tests
191# in this file. They are still here.
danielk1977def0fec2007-05-10 15:37:52 +0000192do_test fuzz-1.1 {
193 execsql {
194 SELECT 'abc' LIKE X'ABCD';
195 }
196} {0}
197do_test fuzz-1.2 {
198 execsql {
199 SELECT 'abc' LIKE zeroblob(10);
200 }
201} {0}
202do_test fuzz-1.3 {
203 execsql {
204 SELECT zeroblob(10) LIKE 'abc';
205 }
206} {0}
207do_test fuzz-1.4 {
208 execsql {
209 SELECT (- -21) % NOT (456 LIKE zeroblob(10));
210 }
211} {0}
danielk1977f75232f2007-05-10 17:32:48 +0000212do_test fuzz-1.5 {
213 execsql {
214 SELECT (SELECT (
215 SELECT (SELECT -2147483648) FROM (SELECT 1) ORDER BY 1
216 ))
danielk1977def0fec2007-05-10 15:37:52 +0000217 }
danielk1977f75232f2007-05-10 17:32:48 +0000218} {-2147483648}
219do_test fuzz-1.6 {
220 execsql {
221 SELECT 'abc', zeroblob(1) FROM (SELECT 1) ORDER BY 1
222 }
223} [execsql {SELECT 'abc', zeroblob(1)}]
224
225do_test fuzz-1.7 {
226 execsql {
danielk1977d908f5a2007-05-11 07:08:28 +0000227 SELECT ( SELECT zeroblob(1000) FROM (
228 SELECT * FROM (SELECT 'first') ORDER BY NOT 'in')
danielk1977639f45f2007-05-10 17:38:57 +0000229 )
danielk1977f75232f2007-05-10 17:32:48 +0000230 }
danielk1977d908f5a2007-05-11 07:08:28 +0000231} [execsql {SELECT zeroblob(1000)}]
danielk1977def0fec2007-05-10 15:37:52 +0000232
danielk1977bcfc4bc2007-05-11 10:10:33 +0000233do_test fuzz-1.8 {
234 execsql {
235 SELECT CAST(zeroblob(1000) AS text);
236 }
237} {{}}
238
danielk1977f75232f2007-05-10 17:32:48 +0000239#----------------------------------------------------------------
240# Test some fuzzily generated expressions.
241#
danielk1977bcfc4bc2007-05-11 10:10:33 +0000242do_fuzzy_test fuzz-2 -template { SELECT [Expr] }
danielk1977f75232f2007-05-10 17:32:48 +0000243
244do_test fuzz-3.1 {
245 execsql {
246 CREATE TABLE abc(a, b, c);
danielk1977bcfc4bc2007-05-11 10:10:33 +0000247 CREATE TABLE def(a, b, c);
248 CREATE TABLE ghi(a, b, c);
danielk1977f75232f2007-05-10 17:32:48 +0000249 }
250} {}
danielk1977bcfc4bc2007-05-11 10:10:33 +0000251set ::TableList [list abc def ghi]
252set ::ColumnList [list a b c]
danielk1977f75232f2007-05-10 17:32:48 +0000253
254#----------------------------------------------------------------
255# Test some fuzzily generated SELECT statements.
256#
danielk1977bcfc4bc2007-05-11 10:10:33 +0000257do_fuzzy_test fuzz-3.2 -template {[Select]}
danielk1977f75232f2007-05-10 17:32:48 +0000258
danielk1977bcfc4bc2007-05-11 10:10:33 +0000259#----------------------------------------------------------------
260# Insert a small amount of data into the database and then run
261# some more generated SELECT statements.
262#
263do_test fuzz-4.1 {
264 execsql {
265 INSERT INTO abc VALUES(1, 2, 3);
266 INSERT INTO abc VALUES(4, 5, 6);
267 INSERT INTO abc VALUES(7, 8, 9);
268 INSERT INTO def VALUES(1, 2, 3);
269 INSERT INTO def VALUES(4, 5, 6);
270 INSERT INTO def VALUES(7, 8, 9);
271 INSERT INTO ghi VALUES(1, 2, 3);
272 INSERT INTO ghi VALUES(4, 5, 6);
273 INSERT INTO ghi VALUES(7, 8, 9);
274 CREATE INDEX abc_i ON abc(a, b, c);
275 CREATE INDEX def_i ON def(c, a, b);
276 CREATE INDEX ghi_i ON ghi(b, c, a);
277 }
278} {}
279do_fuzzy_test fuzz-4.2 -template {[Select]}
280
281#----------------------------------------------------------------
282# Test some fuzzy INSERT statements:
283#
284do_test fuzz-5.1 {execsql BEGIN} {}
285do_fuzzy_test fuzz-5.2 -template {[Insert]} -errorlist table
286integrity_check fuzz-5.2.integrity
287do_test fuzz-5.3 {execsql COMMIT} {}
288integrity_check fuzz-5.4.integrity
289
290do_fuzzy_test fuzz-6.1 -template {[Select]}
291
292close $::log
danielk1977def0fec2007-05-10 15:37:52 +0000293finish_test