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