xref: /sqlite-3.40.0/test/e_expr.test (revision 784141ea)
1*784141eaSdan# 2010 July 16
2*784141eaSdan#
3*784141eaSdan# The author disclaims copyright to this source code.  In place of
4*784141eaSdan# a legal notice, here is a blessing:
5*784141eaSdan#
6*784141eaSdan#    May you do good and not evil.
7*784141eaSdan#    May you find forgiveness for yourself and forgive others.
8*784141eaSdan#    May you share freely, never taking more than you give.
9*784141eaSdan#
10*784141eaSdan#***********************************************************************
11*784141eaSdan#
12*784141eaSdan# This file implements tests to verify that the "testable statements" in
13*784141eaSdan# the lang_expr.html document are correct.
14*784141eaSdan#
15*784141eaSdan
16*784141eaSdanset testdir [file dirname $argv0]
17*784141eaSdansource $testdir/tester.tcl
18*784141eaSdansource $testdir/malloc_common.tcl
19*784141eaSdan
20*784141eaSdan# Set up three global variables:
21*784141eaSdan#
22*784141eaSdan#   ::opname         An array mapping from SQL operator to an easy to parse
23*784141eaSdan#                    name. The names are used as part of test case names.
24*784141eaSdan#
25*784141eaSdan#   ::opprec         An array mapping from SQL operator to a numeric
26*784141eaSdan#                    precedence value. Operators that group more tightly
27*784141eaSdan#                    have lower numeric precedences.
28*784141eaSdan#
29*784141eaSdan#   ::oplist         A list of all SQL operators supported by SQLite.
30*784141eaSdan#
31*784141eaSdanforeach {op opn} {
32*784141eaSdan      ||   cat     *   mul       /  div       %     mod       +      add
33*784141eaSdan      -    sub     <<  lshift    >> rshift    &     bitand    |      bitor
34*784141eaSdan      <    less    <=  lesseq    >  more      >=    moreeq    =      eq1
35*784141eaSdan      ==   eq2     <>  ne1       != ne2       IS    is        LIKE   like
36*784141eaSdan      GLOB glob    AND and       OR or        MATCH match     REGEXP regexp
37*784141eaSdan      {IS NOT} isnt
38*784141eaSdan} {
39*784141eaSdan  set ::opname($op) $opn
40*784141eaSdan}
41*784141eaSdanset oplist [list]
42*784141eaSdanforeach {prec opl} {
43*784141eaSdan  1   ||
44*784141eaSdan  2   {* / %}
45*784141eaSdan  3   {+ -}
46*784141eaSdan  4   {<< >> & |}
47*784141eaSdan  5   {< <= > >=}
48*784141eaSdan  6   {= == != <> IS {IS NOT} LIKE GLOB MATCH REGEXP}
49*784141eaSdan  7   AND
50*784141eaSdan  8   OR
51*784141eaSdan} {
52*784141eaSdan  foreach op $opl {
53*784141eaSdan    set ::opprec($op) $prec
54*784141eaSdan    lappend oplist $op
55*784141eaSdan  }
56*784141eaSdan}
57*784141eaSdan
58*784141eaSdan
59*784141eaSdan# Hook in definitions of MATCH and REGEX. The following implementations
60*784141eaSdan# cause MATCH and REGEX to behave similarly to the == operator.
61*784141eaSdan#
62*784141eaSdanproc matchfunc {a b} { return [expr {$a==$b}] }
63*784141eaSdanproc regexfunc {a b} { return [expr {$a==$b}] }
64*784141eaSdandb func match  -argcount 2 matchfunc
65*784141eaSdandb func regexp -argcount 2 regexfunc
66*784141eaSdan
67*784141eaSdan#-------------------------------------------------------------------------
68*784141eaSdan# Test cases e_expr-1.* attempt to verify that all binary operators listed
69*784141eaSdan# in the documentation exist and that the relative precedences of the
70*784141eaSdan# operators are also as the documentation suggests.
71*784141eaSdan#
72*784141eaSdan# EVIDENCE-OF: R-15514-65163 SQLite understands the following binary
73*784141eaSdan# operators, in order from highest to lowest precedence: || * / % + -
74*784141eaSdan# << >> & | < <= > >= = == != <> IS IS
75*784141eaSdan# NOT IN LIKE GLOB MATCH REGEXP AND OR
76*784141eaSdan#
77*784141eaSdan# EVIDENCE-OF: R-38759-38789 Operators IS and IS NOT have the same
78*784141eaSdan# precedence as =.
79*784141eaSdan#
80*784141eaSdan
81*784141eaSdan
82*784141eaSdan# TODO: These tests are currently omitted because one or two cases
83*784141eaSdan# related to LIKE/GLOB/MATCH/REGEXP fail. After this case is fixed,
84*784141eaSdan# reinstate these tests.
85*784141eaSdan#
86*784141eaSdanif 0 {
87*784141eaSdan
88*784141eaSdanunset -nocomplain untested
89*784141eaSdanforeach op1 $oplist {
90*784141eaSdan  foreach op2 $oplist {
91*784141eaSdan    set untested($op1,$op2) 1
92*784141eaSdan    foreach {tn A B C} {
93*784141eaSdan       1     22   45    66
94*784141eaSdan       2      0    0     0
95*784141eaSdan       3      0    0     1
96*784141eaSdan       4      0    1     0
97*784141eaSdan       5      0    1     1
98*784141eaSdan       6      1    0     0
99*784141eaSdan       7      1    0     1
100*784141eaSdan       8      1    1     0
101*784141eaSdan       9      1    1     1
102*784141eaSdan      10      5    6     1
103*784141eaSdan      11      1    5     6
104*784141eaSdan      12      1    5     5
105*784141eaSdan      13      5    5     1
106*784141eaSdan
107*784141eaSdan      14      5    2     1
108*784141eaSdan      15      1    4     1
109*784141eaSdan      16     -1    0     1
110*784141eaSdan      17      0    1    -1
111*784141eaSdan
112*784141eaSdan    } {
113*784141eaSdan      set testname "e_expr-1.$opname($op1).$opname($op2).$tn"
114*784141eaSdan
115*784141eaSdan      # If $op2 groups more tightly than $op1, then the result
116*784141eaSdan      # of executing $sql1 whould be the same as executing $sql3.
117*784141eaSdan      # If $op1 groups more tightly, or if $op1 and $op2 have
118*784141eaSdan      # the same precedence, then executing $sql1 should return
119*784141eaSdan      # the same value as $sql2.
120*784141eaSdan      #
121*784141eaSdan      set sql1 "SELECT $A $op1 $B $op2 $C"
122*784141eaSdan      set sql2 "SELECT ($A $op1 $B) $op2 $C"
123*784141eaSdan      set sql3 "SELECT $A $op1 ($B $op2 $C)"
124*784141eaSdan
125*784141eaSdan      set a2 [db one $sql2]
126*784141eaSdan      set a3 [db one $sql3]
127*784141eaSdan
128*784141eaSdan      do_execsql_test $testname $sql1 [list [
129*784141eaSdan        expr {$opprec($op2) < $opprec($op1) ? $a3 : $a2}
130*784141eaSdan      ]]
131*784141eaSdan
132*784141eaSdan      if {$a2 != $a3} { unset -nocomplain untested($op1,$op2) }
133*784141eaSdan    }
134*784141eaSdan  }
135*784141eaSdan}
136*784141eaSdan
137*784141eaSdanforeach op {* AND OR + || & |} { unset untested($op,$op) }
138*784141eaSdanunset untested(+,-)  ;#       Since    (a+b)-c == a+(b-c)
139*784141eaSdanunset untested(*,<<) ;#       Since    (a*b)<<c == a*(b<<c)
140*784141eaSdan
141*784141eaSdando_test e_expr-1.1 { array names untested } {}
142*784141eaSdan
143*784141eaSdan# At one point, test 1.2.2 was failing. Instead of the correct result, it
144*784141eaSdan# was returning {1 1 0}. This would seem to indicate that LIKE has the
145*784141eaSdan# same precedence as '<'. Which is incorrect. It has lower precedence.
146*784141eaSdan#
147*784141eaSdando_execsql_test e_expr-1.2.1 {
148*784141eaSdan  SELECT 0 < 2 LIKE 1,   (0 < 2) LIKE 1,   0 < (2 LIKE 1)
149*784141eaSdan} {1 1 0}
150*784141eaSdando_execsql_test e_expr-1.2.2 {
151*784141eaSdan  SELECT 0 LIKE 0 < 2,   (0 LIKE 0) < 2,   0 LIKE (0 < 2)
152*784141eaSdan} {0 1 0}
153*784141eaSdan
154*784141eaSdan# Showing that LIKE and == have the same precedence
155*784141eaSdan#
156*784141eaSdando_execsql_test e_expr-1.2.3 {
157*784141eaSdan  SELECT 2 LIKE 2 == 1,   (2 LIKE 2) == 1,    2 LIKE (2 == 1)
158*784141eaSdan} {1 1 0}
159*784141eaSdando_execsql_test e_expr-1.2.4 {
160*784141eaSdan  SELECT 2 == 2 LIKE 1,   (2 == 2) LIKE 1,    2 == (2 LIKE 1)
161*784141eaSdan} {1 1 0}
162*784141eaSdan
163*784141eaSdan# Showing that < groups more tightly than == (< has higher precedence).
164*784141eaSdan#
165*784141eaSdando_execsql_test e_expr-1.2.5 {
166*784141eaSdan  SELECT 0 < 2 == 1,   (0 < 2) == 1,   0 < (2 == 1)
167*784141eaSdan} {1 1 0}
168*784141eaSdando_execsql_test e_expr-1.6 {
169*784141eaSdan  SELECT 0 == 0 < 2,   (0 == 0) < 2,   0 == (0 < 2)
170*784141eaSdan} {0 1 0}
171*784141eaSdan
172*784141eaSdan}
173*784141eaSdan
174*784141eaSdan#-------------------------------------------------------------------------
175*784141eaSdan# Check that the four unary prefix operators mentioned in the
176*784141eaSdan# documentation exist.
177*784141eaSdan#
178*784141eaSdan# EVIDENCE-OF: R-13958-53419 Supported unary prefix operators are these:
179*784141eaSdan# - + ~ NOT
180*784141eaSdan#
181*784141eaSdando_execsql_test e_expr-2.1 { SELECT -   10   } {-10}
182*784141eaSdando_execsql_test e_expr-2.2 { SELECT +   10   } {10}
183*784141eaSdando_execsql_test e_expr-2.3 { SELECT ~   10   } {-11}
184*784141eaSdando_execsql_test e_expr-2.4 { SELECT NOT 10   } {0}
185*784141eaSdan
186*784141eaSdan#-------------------------------------------------------------------------
187*784141eaSdan# Tests for the two statements made regarding the unary + operator.
188*784141eaSdan#
189*784141eaSdan# EVIDENCE-OF: R-53670-03373 The unary operator + is a no-op.
190*784141eaSdan#
191*784141eaSdan# EVIDENCE-OF: R-19480-30968 It can be applied to strings, numbers,
192*784141eaSdan# blobs or NULL and it always returns a result with the same value as
193*784141eaSdan# the operand.
194*784141eaSdan#
195*784141eaSdanforeach {tn literal type} {
196*784141eaSdan  1     'helloworld'   text
197*784141eaSdan  2     45             integer
198*784141eaSdan  3     45.2           real
199*784141eaSdan  4     45.0           real
200*784141eaSdan  5     X'ABCDEF'      blob
201*784141eaSdan  6     NULL           null
202*784141eaSdan} {
203*784141eaSdan  set sql " SELECT quote( + $literal ), typeof( + $literal) "
204*784141eaSdan  do_execsql_test e_expr-3.$tn $sql [list $literal $type]
205*784141eaSdan}
206*784141eaSdan
207*784141eaSdan#-------------------------------------------------------------------------
208*784141eaSdan# Check that both = and == are both acceptable as the "equals" operator.
209*784141eaSdan# Similarly, either != or <> work as the not-equals operator.
210*784141eaSdan#
211*784141eaSdan# EVIDENCE-OF: R-03679-60639 Equals can be either = or ==.
212*784141eaSdan#
213*784141eaSdan# EVIDENCE-OF: R-30082-38996 The non-equals operator can be either != or
214*784141eaSdan# <>.
215*784141eaSdan#
216*784141eaSdanforeach {tn literal different} {
217*784141eaSdan  1   'helloworld'  '12345'
218*784141eaSdan  2   22            23
219*784141eaSdan  3   'xyz'         X'78797A'
220*784141eaSdan  4   X'78797A00'   'xyz'
221*784141eaSdan} {
222*784141eaSdan  do_execsql_test e_expr-4.$tn "
223*784141eaSdan    SELECT $literal  = $literal,   $literal == $literal,
224*784141eaSdan           $literal  = $different, $literal == $different,
225*784141eaSdan           $literal  = NULL,       $literal == NULL,
226*784141eaSdan           $literal != $literal,   $literal <> $literal,
227*784141eaSdan           $literal != $different, $literal <> $different,
228*784141eaSdan           $literal != NULL,       $literal != NULL
229*784141eaSdan
230*784141eaSdan  " {1 1 0 0 {} {} 0 0 1 1 {} {}}
231*784141eaSdan}
232*784141eaSdan
233*784141eaSdan#-------------------------------------------------------------------------
234*784141eaSdan# Test the || operator.
235*784141eaSdan#
236*784141eaSdan# EVIDENCE-OF: R-44409-62641 The || operator is "concatenate" - it joins
237*784141eaSdan# together the two strings of its operands.
238*784141eaSdan#
239*784141eaSdanforeach {tn a b} {
240*784141eaSdan  1   'helloworld'  '12345'
241*784141eaSdan  2   22            23
242*784141eaSdan} {
243*784141eaSdan  set as [db one "SELECT $a"]
244*784141eaSdan  set bs [db one "SELECT $b"]
245*784141eaSdan
246*784141eaSdan  do_execsql_test e_expr-5.$tn "SELECT $a || $b" [list "${as}${bs}"]
247*784141eaSdan}
248*784141eaSdan
249*784141eaSdan#-------------------------------------------------------------------------
250*784141eaSdan# Test the % operator.
251*784141eaSdan#
252*784141eaSdan# EVIDENCE-OF: R-08914-63790 The operator % outputs the value of its
253*784141eaSdan# left operand modulo its right operand.
254*784141eaSdan#
255*784141eaSdando_execsql_test e_expr-6.1 {SELECT  72%5}  {2}
256*784141eaSdando_execsql_test e_expr-6.2 {SELECT  72%-5} {2}
257*784141eaSdando_execsql_test e_expr-6.3 {SELECT -72%-5} {-2}
258*784141eaSdando_execsql_test e_expr-6.4 {SELECT -72%5}  {-2}
259*784141eaSdan
260*784141eaSdan#-------------------------------------------------------------------------
261*784141eaSdan# Test that the results of all binary operators are either numeric or
262*784141eaSdan# NULL, except for the || operator, which may evaluate to either a text
263*784141eaSdan# value or NULL.
264*784141eaSdan#
265*784141eaSdan# EVIDENCE-OF: R-20665-17792 The result of any binary operator is either
266*784141eaSdan# a numeric value or NULL, except for the || concatenation operator
267*784141eaSdan# which always evaluates to either NULL or a text value.
268*784141eaSdan#
269*784141eaSdanset literals {
270*784141eaSdan  1 'abc'        2 'hexadecimal'       3 ''
271*784141eaSdan  4 123          5 -123                6 0
272*784141eaSdan  7 123.4        8 0.0                 9 -123.4
273*784141eaSdan 10 X'ABCDEF'   11 X''                12 X'0000'
274*784141eaSdan 13     NULL
275*784141eaSdan}
276*784141eaSdanforeach op $oplist {
277*784141eaSdan  foreach {n1 rhs} $literals {
278*784141eaSdan  foreach {n2 lhs} $literals {
279*784141eaSdan
280*784141eaSdan    set t [db one " SELECT typeof($lhs $op $rhs) "]
281*784141eaSdan    do_test e_expr-7.$opname($op).$n1.$n2 {
282*784141eaSdan      expr {
283*784141eaSdan           ($op=="||" && ($t == "text" || $t == "null"))
284*784141eaSdan        || ($op!="||" && ($t == "integer" || $t == "real" || $t == "null"))
285*784141eaSdan      }
286*784141eaSdan    } 1
287*784141eaSdan
288*784141eaSdan  }}
289*784141eaSdan}
290*784141eaSdan
291*784141eaSdan#-------------------------------------------------------------------------
292*784141eaSdan# Test the IS and IS NOT operators.
293*784141eaSdan#
294*784141eaSdan# EVIDENCE-OF: R-24731-45773 The IS and IS NOT operators work like = and
295*784141eaSdan# != except when one or both of the operands are NULL.
296*784141eaSdan#
297*784141eaSdan# EVIDENCE-OF: R-06325-15315 In this case, if both operands are NULL,
298*784141eaSdan# then the IS operator evaluates to 1 (true) and the IS NOT operator
299*784141eaSdan# evaluates to 0 (false).
300*784141eaSdan#
301*784141eaSdan# EVIDENCE-OF: R-19812-36779 If one operand is NULL and the other is
302*784141eaSdan# not, then the IS operator evaluates to 0 (false) and the IS NOT
303*784141eaSdan# operator is 1 (true).
304*784141eaSdan#
305*784141eaSdan# EVIDENCE-OF: R-61975-13410 It is not possible for an IS or IS NOT
306*784141eaSdan# expression to evaluate to NULL.
307*784141eaSdan#
308*784141eaSdando_execsql_test e_expr-8.1.1  { SELECT NULL IS     NULL } {1}
309*784141eaSdando_execsql_test e_expr-8.1.2  { SELECT 'ab' IS     NULL } {0}
310*784141eaSdando_execsql_test e_expr-8.1.3  { SELECT NULL IS     'ab' } {0}
311*784141eaSdando_execsql_test e_expr-8.1.4  { SELECT 'ab' IS     'ab' } {1}
312*784141eaSdando_execsql_test e_expr-8.1.5  { SELECT NULL ==     NULL } {{}}
313*784141eaSdando_execsql_test e_expr-8.1.6  { SELECT 'ab' ==     NULL } {{}}
314*784141eaSdando_execsql_test e_expr-8.1.7  { SELECT NULL ==     'ab' } {{}}
315*784141eaSdando_execsql_test e_expr-8.1.8  { SELECT 'ab' ==     'ab' } {1}
316*784141eaSdando_execsql_test e_expr-8.1.9  { SELECT NULL IS NOT NULL } {0}
317*784141eaSdando_execsql_test e_expr-8.1.10 { SELECT 'ab' IS NOT NULL } {1}
318*784141eaSdando_execsql_test e_expr-8.1.11 { SELECT NULL IS NOT 'ab' } {1}
319*784141eaSdando_execsql_test e_expr-8.1.12 { SELECT 'ab' IS NOT 'ab' } {0}
320*784141eaSdando_execsql_test e_expr-8.1.13 { SELECT NULL !=     NULL } {{}}
321*784141eaSdando_execsql_test e_expr-8.1.14 { SELECT 'ab' !=     NULL } {{}}
322*784141eaSdando_execsql_test e_expr-8.1.15 { SELECT NULL !=     'ab' } {{}}
323*784141eaSdando_execsql_test e_expr-8.1.16 { SELECT 'ab' !=     'ab' } {0}
324*784141eaSdan
325*784141eaSdanforeach {n1 rhs} $literals {
326*784141eaSdan  foreach {n2 lhs} $literals {
327*784141eaSdan    if {$rhs!="NULL" && $lhs!="NULL"} {
328*784141eaSdan      set eq [execsql "SELECT $lhs = $rhs, $lhs != $rhs"]
329*784141eaSdan    } else {
330*784141eaSdan      set eq [list [expr {$lhs=="NULL" && $rhs=="NULL"}] \
331*784141eaSdan                   [expr {$lhs!="NULL" || $rhs!="NULL"}]
332*784141eaSdan      ]
333*784141eaSdan    }
334*784141eaSdan    set test e_expr-8.2.$n1.$n2
335*784141eaSdan    do_execsql_test $test.1 "SELECT $lhs IS $rhs, $lhs IS NOT $rhs" $eq
336*784141eaSdan    do_execsql_test $test.2 "
337*784141eaSdan      SELECT ($lhs IS $rhs) IS NULL, ($lhs IS NOT $rhs) IS NULL
338*784141eaSdan    " {0 0}
339*784141eaSdan  }
340*784141eaSdan}
341*784141eaSdan
342*784141eaSdanfinish_test
343