OLD | NEW |
| (Empty) |
1 # Run this TCL script to generate thousands of test cases containing | |
2 # complicated expressions. | |
3 # | |
4 # The generated tests are intended to verify expression evaluation | |
5 # in SQLite against expression evaluation TCL. | |
6 # | |
7 | |
8 # Terms of the $intexpr list each contain two sub-terms. | |
9 # | |
10 # * An SQL expression template | |
11 # * The equivalent TCL expression | |
12 # | |
13 # EXPR is replaced by an integer subexpression. BOOL is replaced | |
14 # by a boolean subexpression. | |
15 # | |
16 set intexpr { | |
17 {11 wide(11)} | |
18 {13 wide(13)} | |
19 {17 wide(17)} | |
20 {19 wide(19)} | |
21 {a $a} | |
22 {b $b} | |
23 {c $c} | |
24 {d $d} | |
25 {e $e} | |
26 {f $f} | |
27 {t1.a $a} | |
28 {t1.b $b} | |
29 {t1.c $c} | |
30 {t1.d $d} | |
31 {t1.e $e} | |
32 {t1.f $f} | |
33 {(EXPR) (EXPR)} | |
34 {{ -EXPR} {-EXPR}} | |
35 {+EXPR +EXPR} | |
36 {~EXPR ~EXPR} | |
37 {EXPR+EXPR EXPR+EXPR} | |
38 {EXPR-EXPR EXPR-EXPR} | |
39 {EXPR*EXPR EXPR*EXPR} | |
40 {EXPR+EXPR EXPR+EXPR} | |
41 {EXPR-EXPR EXPR-EXPR} | |
42 {EXPR*EXPR EXPR*EXPR} | |
43 {EXPR+EXPR EXPR+EXPR} | |
44 {EXPR-EXPR EXPR-EXPR} | |
45 {EXPR*EXPR EXPR*EXPR} | |
46 {{EXPR | EXPR} {EXPR | EXPR}} | |
47 {(abs(EXPR)/abs(EXPR)) (abs(EXPR)/abs(EXPR))} | |
48 { | |
49 {case when BOOL then EXPR else EXPR end} | |
50 {((BOOL)?EXPR:EXPR)} | |
51 } | |
52 { | |
53 {case when BOOL then EXPR when BOOL then EXPR else EXPR end} | |
54 {((BOOL)?EXPR:((BOOL)?EXPR:EXPR))} | |
55 } | |
56 { | |
57 {case EXPR when EXPR then EXPR else EXPR end} | |
58 {(((EXPR)==(EXPR))?EXPR:EXPR)} | |
59 } | |
60 { | |
61 {(select AGG from t1)} | |
62 {(AGG)} | |
63 } | |
64 { | |
65 {coalesce((select max(EXPR) from t1 where BOOL),EXPR)} | |
66 {[coalesce_subquery [expr {EXPR}] [expr {BOOL}] [expr {EXPR}]]} | |
67 } | |
68 { | |
69 {coalesce((select EXPR from t1 where BOOL),EXPR)} | |
70 {[coalesce_subquery [expr {EXPR}] [expr {BOOL}] [expr {EXPR}]]} | |
71 } | |
72 } | |
73 | |
74 # The $boolexpr list contains terms that show both an SQL boolean | |
75 # expression and its equivalent TCL. | |
76 # | |
77 set boolexpr { | |
78 {EXPR=EXPR ((EXPR)==(EXPR))} | |
79 {EXPR<EXPR ((EXPR)<(EXPR))} | |
80 {EXPR>EXPR ((EXPR)>(EXPR))} | |
81 {EXPR<=EXPR ((EXPR)<=(EXPR))} | |
82 {EXPR>=EXPR ((EXPR)>=(EXPR))} | |
83 {EXPR<>EXPR ((EXPR)!=(EXPR))} | |
84 { | |
85 {EXPR between EXPR and EXPR} | |
86 {[betweenop [expr {EXPR}] [expr {EXPR}] [expr {EXPR}]]} | |
87 } | |
88 { | |
89 {EXPR not between EXPR and EXPR} | |
90 {(![betweenop [expr {EXPR}] [expr {EXPR}] [expr {EXPR}]])} | |
91 } | |
92 { | |
93 {EXPR in (EXPR,EXPR,EXPR)} | |
94 {([inop [expr {EXPR}] [expr {EXPR}] [expr {EXPR}] [expr {EXPR}]])} | |
95 } | |
96 { | |
97 {EXPR not in (EXPR,EXPR,EXPR)} | |
98 {(![inop [expr {EXPR}] [expr {EXPR}] [expr {EXPR}] [expr {EXPR}]])} | |
99 } | |
100 { | |
101 {EXPR in (select EXPR from t1 union select EXPR from t1)} | |
102 {[inop [expr {EXPR}] [expr {EXPR}] [expr {EXPR}]]} | |
103 } | |
104 { | |
105 {EXPR in (select AGG from t1 union select AGG from t1)} | |
106 {[inop [expr {EXPR}] [expr {AGG}] [expr {AGG}]]} | |
107 } | |
108 { | |
109 {exists(select 1 from t1 where BOOL)} | |
110 {(BOOL)} | |
111 } | |
112 { | |
113 {not exists(select 1 from t1 where BOOL)} | |
114 {!(BOOL)} | |
115 } | |
116 {{not BOOL} !BOOL} | |
117 {{BOOL and BOOL} {BOOL tcland BOOL}} | |
118 {{BOOL or BOOL} {BOOL || BOOL}} | |
119 {{BOOL and BOOL} {BOOL tcland BOOL}} | |
120 {{BOOL or BOOL} {BOOL || BOOL}} | |
121 {(BOOL) (BOOL)} | |
122 {(BOOL) (BOOL)} | |
123 } | |
124 | |
125 # Aggregate expressions | |
126 # | |
127 set aggexpr { | |
128 {count(*) wide(1)} | |
129 {{count(distinct EXPR)} {[one {EXPR}]}} | |
130 {{cast(avg(EXPR) AS integer)} (EXPR)} | |
131 {min(EXPR) (EXPR)} | |
132 {max(EXPR) (EXPR)} | |
133 {(AGG) (AGG)} | |
134 {{ -AGG} {-AGG}} | |
135 {+AGG +AGG} | |
136 {~AGG ~AGG} | |
137 {abs(AGG) abs(AGG)} | |
138 {AGG+AGG AGG+AGG} | |
139 {AGG-AGG AGG-AGG} | |
140 {AGG*AGG AGG*AGG} | |
141 {{AGG | AGG} {AGG | AGG}} | |
142 { | |
143 {case AGG when AGG then AGG else AGG end} | |
144 {(((AGG)==(AGG))?AGG:AGG)} | |
145 } | |
146 } | |
147 | |
148 # Convert a string containing EXPR, AGG, and BOOL into a string | |
149 # that contains nothing but X, Y, and Z. | |
150 # | |
151 proc extract_vars {a} { | |
152 regsub -all {EXPR} $a X a | |
153 regsub -all {AGG} $a Y a | |
154 regsub -all {BOOL} $a Z a | |
155 regsub -all {[^XYZ]} $a {} a | |
156 return $a | |
157 } | |
158 | |
159 | |
160 # Test all templates to make sure the number of EXPR, AGG, and BOOL | |
161 # expressions match. | |
162 # | |
163 foreach term [concat $aggexpr $intexpr $boolexpr] { | |
164 foreach {a b} $term break | |
165 if {[extract_vars $a]!=[extract_vars $b]} { | |
166 error "mismatch: $term" | |
167 } | |
168 } | |
169 | |
170 # Generate a random expression according to the templates given above. | |
171 # If the argument is EXPR or omitted, then an integer expression is | |
172 # generated. If the argument is BOOL then a boolean expression is | |
173 # produced. | |
174 # | |
175 proc generate_expr {{e EXPR}} { | |
176 set tcle $e | |
177 set ne [llength $::intexpr] | |
178 set nb [llength $::boolexpr] | |
179 set na [llength $::aggexpr] | |
180 set div 2 | |
181 set mx 50 | |
182 set i 0 | |
183 while {1} { | |
184 set cnt 0 | |
185 set re [lindex $::intexpr [expr {int(rand()*$ne)}]] | |
186 incr cnt [regsub {EXPR} $e [lindex $re 0] e] | |
187 regsub {EXPR} $tcle [lindex $re 1] tcle | |
188 set rb [lindex $::boolexpr [expr {int(rand()*$nb)}]] | |
189 incr cnt [regsub {BOOL} $e [lindex $rb 0] e] | |
190 regsub {BOOL} $tcle [lindex $rb 1] tcle | |
191 set ra [lindex $::aggexpr [expr {int(rand()*$na)}]] | |
192 incr cnt [regsub {AGG} $e [lindex $ra 0] e] | |
193 regsub {AGG} $tcle [lindex $ra 1] tcle | |
194 | |
195 if {$cnt==0} break | |
196 incr i $cnt | |
197 | |
198 set v1 [extract_vars $e] | |
199 if {$v1!=[extract_vars $tcle]} { | |
200 exit | |
201 } | |
202 | |
203 if {$i+[string length $v1]>=$mx} { | |
204 set ne [expr {$ne/$div}] | |
205 set nb [expr {$nb/$div}] | |
206 set na [expr {$na/$div}] | |
207 set div 1 | |
208 set mx [expr {$mx*1000}] | |
209 } | |
210 } | |
211 regsub -all { tcland } $tcle { \&\& } tcle | |
212 return [list $e $tcle] | |
213 } | |
214 | |
215 # Implementation of routines used to implement the IN and BETWEEN | |
216 # operators. | |
217 proc inop {lhs args} { | |
218 foreach a $args { | |
219 if {$a==$lhs} {return 1} | |
220 } | |
221 return 0 | |
222 } | |
223 proc betweenop {lhs first second} { | |
224 return [expr {$lhs>=$first && $lhs<=$second}] | |
225 } | |
226 proc coalesce_subquery {a b e} { | |
227 if {$b} { | |
228 return $a | |
229 } else { | |
230 return $e | |
231 } | |
232 } | |
233 proc one {args} { | |
234 return 1 | |
235 } | |
236 | |
237 # Begin generating the test script: | |
238 # | |
239 puts {# 2008 December 16 | |
240 # | |
241 # The author disclaims copyright to this source code. In place of | |
242 # a legal notice, here is a blessing: | |
243 # | |
244 # May you do good and not evil. | |
245 # May you find forgiveness for yourself and forgive others. | |
246 # May you share freely, never taking more than you give. | |
247 # | |
248 #*********************************************************************** | |
249 # This file implements regression tests for SQLite library. | |
250 # | |
251 # This file tests randomly generated SQL expressions. The expressions | |
252 # are generated by a TCL script. The same TCL script also computes the | |
253 # correct value of the expression. So, from one point of view, this | |
254 # file verifies the expression evaluation logic of SQLite against the | |
255 # expression evaluation logic of TCL. | |
256 # | |
257 # An early version of this script is how bug #3541 was detected. | |
258 # | |
259 # $Id: randexpr1.tcl,v 1.1 2008/12/15 16:33:30 drh Exp $ | |
260 set testdir [file dirname $argv0] | |
261 source $testdir/tester.tcl | |
262 | |
263 # Create test data | |
264 # | |
265 do_test randexpr1-1.1 { | |
266 db eval { | |
267 CREATE TABLE t1(a,b,c,d,e,f); | |
268 INSERT INTO t1 VALUES(100,200,300,400,500,600); | |
269 SELECT * FROM t1 | |
270 } | |
271 } {100 200 300 400 500 600} | |
272 } | |
273 | |
274 # Test data for TCL evaluation. | |
275 # | |
276 set a [expr {wide(100)}] | |
277 set b [expr {wide(200)}] | |
278 set c [expr {wide(300)}] | |
279 set d [expr {wide(400)}] | |
280 set e [expr {wide(500)}] | |
281 set f [expr {wide(600)}] | |
282 | |
283 # A procedure to generate a test case. | |
284 # | |
285 set tn 0 | |
286 proc make_test_case {sql result} { | |
287 global tn | |
288 incr tn | |
289 puts "do_test randexpr-2.$tn {\n db eval {$sql}\n} {$result}" | |
290 } | |
291 | |
292 # Generate many random test cases. | |
293 # | |
294 expr srand(0) | |
295 for {set i 0} {$i<1000} {incr i} { | |
296 while {1} { | |
297 foreach {sqle tcle} [generate_expr EXPR] break; | |
298 if {[catch {expr $tcle} ans]} { | |
299 #puts stderr [list $tcle] | |
300 #puts stderr ans=$ans | |
301 if {![regexp {divide by zero} $ans]} exit | |
302 continue | |
303 } | |
304 set len [string length $sqle] | |
305 if {$len<100 || $len>2000} continue | |
306 if {[info exists seen($sqle)]} continue | |
307 set seen($sqle) 1 | |
308 break | |
309 } | |
310 while {1} { | |
311 foreach {sqlb tclb} [generate_expr BOOL] break; | |
312 if {[catch {expr $tclb} bans]} { | |
313 #puts stderr [list $tclb] | |
314 #puts stderr bans=$bans | |
315 if {![regexp {divide by zero} $bans]} exit | |
316 continue | |
317 } | |
318 break | |
319 } | |
320 if {$bans} { | |
321 make_test_case "SELECT $sqle FROM t1 WHERE $sqlb" $ans | |
322 make_test_case "SELECT $sqle FROM t1 WHERE NOT ($sqlb)" {} | |
323 } else { | |
324 make_test_case "SELECT $sqle FROM t1 WHERE $sqlb" {} | |
325 make_test_case "SELECT $sqle FROM t1 WHERE NOT ($sqlb)" $ans | |
326 } | |
327 if {[regexp { \| } $sqle]} { | |
328 regsub -all { \| } $sqle { \& } sqle | |
329 regsub -all { \| } $tcle { \& } tcle | |
330 if {[catch {expr $tcle} ans]==0} { | |
331 if {$bans} { | |
332 make_test_case "SELECT $sqle FROM t1 WHERE $sqlb" $ans | |
333 } else { | |
334 make_test_case "SELECT $sqle FROM t1 WHERE NOT ($sqlb)" $ans | |
335 } | |
336 } | |
337 } | |
338 } | |
339 | |
340 # Terminate the test script | |
341 # | |
342 puts {finish_test} | |
OLD | NEW |