xref: /sqlite-3.40.0/test/fts3expr3.test (revision f24bebe3)
1aa29c86eSdan# 2009 January 1
2aa29c86eSdan#
3aa29c86eSdan# The author disclaims copyright to this source code.  In place of
4aa29c86eSdan# a legal notice, here is a blessing:
5aa29c86eSdan#
6aa29c86eSdan#    May you do good and not evil.
7aa29c86eSdan#    May you find forgiveness for yourself and forgive others.
8aa29c86eSdan#    May you share freely, never taking more than you give.
9aa29c86eSdan#
10aa29c86eSdan#*************************************************************************
11aa29c86eSdan# This file implements regression tests for SQLite library.  The
12aa29c86eSdan# focus of this script is testing the part of the FTS3 expression
13aa29c86eSdan# parser that rebalances large expressions.
14aa29c86eSdan#
15aa29c86eSdan# $Id: fts3expr2.test,v 1.2 2009/06/05 17:09:12 drh Exp $
16aa29c86eSdan#
17aa29c86eSdan
18aa29c86eSdanset testdir [file dirname $argv0]
19aa29c86eSdansource $testdir/tester.tcl
20aa29c86eSdansource $testdir/malloc_common.tcl
21aa29c86eSdanset ::testprefix fts3expr3
22aa29c86eSdan
23aa29c86eSdan# If SQLITE_ENABLE_FTS3 is defined, omit this file.
24aa29c86eSdanifcapable !fts3 {
25aa29c86eSdan  finish_test
26aa29c86eSdan  return
27aa29c86eSdan}
28aa29c86eSdan
29aa29c86eSdanset sqlite_fts3_enable_parentheses 1
30aa29c86eSdan
31aa29c86eSdanproc strip_phrase_data {L} {
32aa29c86eSdan  if {[lindex $L 0] eq "PHRASE"} {
33aa29c86eSdan    return [list P [lrange $L 3 end]]
34aa29c86eSdan  }
35aa29c86eSdan  return [list \
36aa29c86eSdan    [lindex $L 0] \
37aa29c86eSdan    [strip_phrase_data [lindex $L 1]] \
38aa29c86eSdan    [strip_phrase_data [lindex $L 2]] \
39aa29c86eSdan  ]
40aa29c86eSdan}
41aa29c86eSdanproc test_fts3expr2 {expr} {
42aa29c86eSdan  strip_phrase_data [
43aa29c86eSdan    db one {SELECT fts3_exprtest_rebalance('simple', $expr, 'a', 'b', 'c')}
44aa29c86eSdan  ]
45aa29c86eSdan}
46aa29c86eSdan
47aa29c86eSdanproc balanced_exprtree_structure {nEntry} {
48aa29c86eSdan  set L [list]
49aa29c86eSdan  for {set i 1} {$i <= $nEntry} {incr i} {
50aa29c86eSdan    lappend L xxx
51aa29c86eSdan  }
52aa29c86eSdan  while {[llength $L] > 1} {
53aa29c86eSdan    set N [list]
54aa29c86eSdan    if {[llength $L] % 2} {
55aa29c86eSdan      foreach {a b} [lrange $L 0 end-1] { lappend N [list AND $a $b] }
56aa29c86eSdan      lappend N [lindex $L end]
57aa29c86eSdan    } else {
58aa29c86eSdan      foreach {a b} $L { lappend N [list AND $a $b] }
59aa29c86eSdan    }
60aa29c86eSdan    set L $N
61aa29c86eSdan  }
62aa29c86eSdan  return [lindex $L 0]
63aa29c86eSdan}
64aa29c86eSdan
65aa29c86eSdanproc balanced_and_tree {nEntry} {
66aa29c86eSdan  set query [balanced_exprtree_structure $nEntry]
67aa29c86eSdan  if {$query == "xxx"} {
68aa29c86eSdan    return "P 1"
69aa29c86eSdan  }
70aa29c86eSdan  for {set i 1} {$i <= $nEntry} {incr i} {
71aa29c86eSdan    regsub xxx $query "{P $i}" query
72aa29c86eSdan  }
73aa29c86eSdan  return $query
74aa29c86eSdan}
75aa29c86eSdan
76aa29c86eSdanproc random_tree_structure {nEntry bParen op} {
77aa29c86eSdan  set query xxx
78aa29c86eSdan  for {set i 1} {$i < $nEntry} {incr i} {
79aa29c86eSdan    set x1 [expr int(rand()*4.0)]
80aa29c86eSdan    set x2 [expr int(rand()*2.0)]
81aa29c86eSdan    if {$x1==0 && $bParen} {
82aa29c86eSdan      set query "($query)"
83aa29c86eSdan    }
84aa29c86eSdan    if {$x2} {
85aa29c86eSdan      set query "xxx $op $query"
86aa29c86eSdan    } else {
87aa29c86eSdan      set query "$query $op xxx"
88aa29c86eSdan    }
89aa29c86eSdan  }
90aa29c86eSdan  return $query
91aa29c86eSdan}
92aa29c86eSdan
93aa29c86eSdanproc random_and_query {nEntry {bParen 0}} {
94aa29c86eSdan  set query [random_tree_structure $nEntry $bParen AND]
95aa29c86eSdan  for {set i 1} {$i <= $nEntry} {incr i} {
96aa29c86eSdan    regsub xxx $query $i query
97aa29c86eSdan  }
98aa29c86eSdan  return $query
99aa29c86eSdan}
100aa29c86eSdan
101aa29c86eSdanproc random_or_query {nEntry} {
102aa29c86eSdan  set query [random_tree_structure $nEntry 1 OR]
103aa29c86eSdan  for {set i 1} {$i <= $nEntry} {incr i} {
104aa29c86eSdan    regsub xxx $query $i query
105aa29c86eSdan  }
106aa29c86eSdan  return $query
107aa29c86eSdan}
108aa29c86eSdan
109aa29c86eSdanproc random_andor_query {nEntry} {
110aa29c86eSdan  set query [random_tree_structure $nEntry 1 AND]
111aa29c86eSdan  for {set i 1} {$i <= $nEntry} {incr i} {
112aa29c86eSdan    regsub xxx $query "([random_or_query $nEntry])" query
113aa29c86eSdan  }
114aa29c86eSdan  return $query
115aa29c86eSdan}
116aa29c86eSdan
117aa29c86eSdanproc balanced_andor_tree {nEntry} {
118aa29c86eSdan  set tree [balanced_exprtree_structure $nEntry]
119aa29c86eSdan  set node "{[balanced_and_tree $nEntry]}"
120aa29c86eSdan  regsub -all AND $node OR node
121aa29c86eSdan  regsub -all xxx $tree $node tree
122aa29c86eSdan  return $tree
123aa29c86eSdan}
124aa29c86eSdan
125*f24bebe3Sdanif 1 {
126*f24bebe3Sdan
127aa29c86eSdan# Test that queries like "1 AND 2 AND 3 AND 4..." are transformed to
128aa29c86eSdan# balanced trees by FTS.
129aa29c86eSdan#
130aa29c86eSdanfor {set i 1} {$i < 100} {incr i} {
131aa29c86eSdan  do_test 1.$i {
132aa29c86eSdan    test_fts3expr2 [random_and_query $i]
133aa29c86eSdan  } [balanced_and_tree $i]
134aa29c86eSdan}
135aa29c86eSdan
136aa29c86eSdan# Same again, except with parenthesis inserted at arbitrary points.
137aa29c86eSdan#
138aa29c86eSdanfor {set i 1} {$i < 100} {incr i} {
139aa29c86eSdan  do_test 2.$i {
140aa29c86eSdan    test_fts3expr2 [random_and_query $i 1]
141aa29c86eSdan  } [balanced_and_tree $i]
142aa29c86eSdan}
143aa29c86eSdan
144aa29c86eSdan# Now attempt to balance two AND trees joined by an OR.
145aa29c86eSdan#
146aa29c86eSdanfor {set i 1} {$i < 100} {incr i} {
147aa29c86eSdan  do_test 3.$i {
148aa29c86eSdan    test_fts3expr2 "[random_and_query $i 1] OR [random_and_query $i 1]"
149aa29c86eSdan  } [list OR [balanced_and_tree $i] [balanced_and_tree $i]]
150aa29c86eSdan}
151aa29c86eSdan
152aa29c86eSdan# Try trees of AND nodes with leaves that are themselves trees of OR nodes.
153aa29c86eSdan#
154181f4f78Sdanfor {set i 2} {$i < 64} {incr i 4} {
155aa29c86eSdan  do_test 3.$i {
156aa29c86eSdan    test_fts3expr2 [random_andor_query $i]
157aa29c86eSdan  } [balanced_andor_tree $i]
158aa29c86eSdan}
159aa29c86eSdan
160aa29c86eSdan# These exceed the depth limit.
161aa29c86eSdan#
162181f4f78Sdanfor {set i 65} {$i < 70} {incr i} {
163aa29c86eSdan  do_test 3.$i {
164aa29c86eSdan    list [catch {test_fts3expr2 [random_andor_query $i]} msg] $msg
165aa29c86eSdan  } {1 {Error parsing expression}}
166aa29c86eSdan}
167aa29c86eSdan
168aa29c86eSdan# This also exceeds the depth limit.
169aa29c86eSdan#
170181f4f78Sdan
171181f4f78Sdando_test 4.1.1 {
172aa29c86eSdan  set q "1"
173aa29c86eSdan  for {set i 2} {$i < 5000} {incr i} {
174aa29c86eSdan    append q " AND $i"
175aa29c86eSdan  }
176aa29c86eSdan  list [catch {test_fts3expr2 $q} msg] $msg
177aa29c86eSdan} {1 {Error parsing expression}}
178181f4f78Sdando_test 4.1.2 {
179181f4f78Sdan  set q "1"
180181f4f78Sdan  for {set i 2} {$i < 4000} {incr i} {
181181f4f78Sdan    append q " AND $i"
182181f4f78Sdan  }
183181f4f78Sdan  catch {test_fts3expr2 $q}
184181f4f78Sdan} {0}
185aa29c86eSdan
186aa29c86eSdanproc create_toggle_tree {nDepth} {
187aa29c86eSdan  if {$nDepth == 0} { return xxx }
188aa29c86eSdan  set nNew [expr $nDepth-1]
189aa29c86eSdan  if {$nDepth % 2} {
190aa29c86eSdan    return "([create_toggle_tree $nNew]) OR ([create_toggle_tree $nNew])"
191aa29c86eSdan  }
192aa29c86eSdan  return "([create_toggle_tree $nNew]) AND ([create_toggle_tree $nNew])"
193aa29c86eSdan}
194aa29c86eSdan
195aa29c86eSdando_test 4.2 {
196aa29c86eSdan  list [catch {test_fts3expr2 [create_toggle_tree 17]} msg] $msg
197aa29c86eSdan} {1 {Error parsing expression}}
198aa29c86eSdan
199aa29c86eSdanset query [random_andor_query 12]
200aa29c86eSdanset result [balanced_andor_tree 12]
201aa29c86eSdando_faultsim_test fts3expr3-fault-1 -faults oom-* -body {
202aa29c86eSdan  test_fts3expr2 $::query
203aa29c86eSdan} -test {
204aa29c86eSdan  faultsim_test_result [list 0 $::result]
205aa29c86eSdan}
206aa29c86eSdan
207*f24bebe3Sdan}
208*f24bebe3Sdan
209*f24bebe3Sdan#-------------------------------------------------------------------
210*f24bebe3Sdan
211*f24bebe3Sdanforeach {tn expr res} {
212*f24bebe3Sdan  1 {1 OR 2 OR 3 OR 4}           {OR {OR {P 1} {P 2}} {OR {P 3} {P 4}}}
213*f24bebe3Sdan  2 {1 OR (2 AND 3 AND 4 AND 5)}
214*f24bebe3Sdan    {OR {P 1} {AND {AND {P 2} {P 3}} {AND {P 4} {P 5}}}}
215*f24bebe3Sdan  3 {(2 AND 3 AND 4 AND 5) OR 1}
216*f24bebe3Sdan    {OR {AND {AND {P 2} {P 3}} {AND {P 4} {P 5}}} {P 1}}
217*f24bebe3Sdan
218*f24bebe3Sdan  4 {1 AND (2 OR 3 OR 4 OR 5)}
219*f24bebe3Sdan    {AND {P 1} {OR {OR {P 2} {P 3}} {OR {P 4} {P 5}}}}
220*f24bebe3Sdan  5 {(2 OR 3 OR 4 OR 5) AND 1}
221*f24bebe3Sdan    {AND {OR {OR {P 2} {P 3}} {OR {P 4} {P 5}}} {P 1}}
222*f24bebe3Sdan
223*f24bebe3Sdan  6 {(2 OR 3 OR 4 OR 5) NOT 1}
224*f24bebe3Sdan    {NOT {OR {OR {P 2} {P 3}} {OR {P 4} {P 5}}} {P 1}}
225*f24bebe3Sdan
226*f24bebe3Sdan  7 {1 NOT (2 OR 3 OR 4 OR 5)}
227*f24bebe3Sdan    {NOT {P 1} {OR {OR {P 2} {P 3}} {OR {P 4} {P 5}}}}
228*f24bebe3Sdan
229*f24bebe3Sdan  8 {(1 OR 2 OR 3 OR 4) NOT (5 AND 6 AND 7 AND 8)}
230*f24bebe3Sdan    {NOT {OR {OR {P 1} {P 2}} {OR {P 3} {P 4}}} {AND {AND {P 5} {P 6}} {AND {P 7} {P 8}}}}
231*f24bebe3Sdan} {
232*f24bebe3Sdan  do_test 5.1.$tn {
233*f24bebe3Sdan    test_fts3expr2 $expr
234*f24bebe3Sdan  } $res
235*f24bebe3Sdan}
236*f24bebe3Sdan
237aa29c86eSdanset sqlite_fts3_enable_parentheses 0
238aa29c86eSdanfinish_test
239