OLD | NEW |
(Empty) | |
| 1 # 2009 January 1 |
| 2 # |
| 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 |
| 12 # focus of this script is testing the part of the FTS3 expression |
| 13 # parser that rebalances large expressions. |
| 14 # |
| 15 # $Id: fts3expr2.test,v 1.2 2009/06/05 17:09:12 drh Exp $ |
| 16 # |
| 17 |
| 18 set testdir [file dirname $argv0] |
| 19 source $testdir/tester.tcl |
| 20 source $testdir/malloc_common.tcl |
| 21 set ::testprefix fts3expr3 |
| 22 |
| 23 # If SQLITE_ENABLE_FTS3 is defined, omit this file. |
| 24 ifcapable !fts3 { |
| 25 finish_test |
| 26 return |
| 27 } |
| 28 |
| 29 set sqlite_fts3_enable_parentheses 1 |
| 30 |
| 31 proc strip_phrase_data {L} { |
| 32 if {[lindex $L 0] eq "PHRASE"} { |
| 33 return [list P [lrange $L 3 end]] |
| 34 } |
| 35 return [list \ |
| 36 [lindex $L 0] \ |
| 37 [strip_phrase_data [lindex $L 1]] \ |
| 38 [strip_phrase_data [lindex $L 2]] \ |
| 39 ] |
| 40 } |
| 41 proc test_fts3expr2 {expr} { |
| 42 strip_phrase_data [ |
| 43 db one {SELECT fts3_exprtest_rebalance('simple', $expr, 'a', 'b', 'c')} |
| 44 ] |
| 45 } |
| 46 |
| 47 proc balanced_exprtree_structure {nEntry} { |
| 48 set L [list] |
| 49 for {set i 1} {$i <= $nEntry} {incr i} { |
| 50 lappend L xxx |
| 51 } |
| 52 while {[llength $L] > 1} { |
| 53 set N [list] |
| 54 if {[llength $L] % 2} { |
| 55 foreach {a b} [lrange $L 0 end-1] { lappend N [list AND $a $b] } |
| 56 lappend N [lindex $L end] |
| 57 } else { |
| 58 foreach {a b} $L { lappend N [list AND $a $b] } |
| 59 } |
| 60 set L $N |
| 61 } |
| 62 return [lindex $L 0] |
| 63 } |
| 64 |
| 65 proc balanced_and_tree {nEntry} { |
| 66 set query [balanced_exprtree_structure $nEntry] |
| 67 if {$query == "xxx"} { |
| 68 return "P 1" |
| 69 } |
| 70 for {set i 1} {$i <= $nEntry} {incr i} { |
| 71 regsub xxx $query "{P $i}" query |
| 72 } |
| 73 return $query |
| 74 } |
| 75 |
| 76 proc random_tree_structure {nEntry bParen op} { |
| 77 set query xxx |
| 78 for {set i 1} {$i < $nEntry} {incr i} { |
| 79 set x1 [expr int(rand()*4.0)] |
| 80 set x2 [expr int(rand()*2.0)] |
| 81 if {$x1==0 && $bParen} { |
| 82 set query "($query)" |
| 83 } |
| 84 if {$x2} { |
| 85 set query "xxx $op $query" |
| 86 } else { |
| 87 set query "$query $op xxx" |
| 88 } |
| 89 } |
| 90 return $query |
| 91 } |
| 92 |
| 93 proc random_and_query {nEntry {bParen 0}} { |
| 94 set query [random_tree_structure $nEntry $bParen AND] |
| 95 for {set i 1} {$i <= $nEntry} {incr i} { |
| 96 regsub xxx $query $i query |
| 97 } |
| 98 return $query |
| 99 } |
| 100 |
| 101 proc random_or_query {nEntry} { |
| 102 set query [random_tree_structure $nEntry 1 OR] |
| 103 for {set i 1} {$i <= $nEntry} {incr i} { |
| 104 regsub xxx $query $i query |
| 105 } |
| 106 return $query |
| 107 } |
| 108 |
| 109 proc random_andor_query {nEntry} { |
| 110 set query [random_tree_structure $nEntry 1 AND] |
| 111 for {set i 1} {$i <= $nEntry} {incr i} { |
| 112 regsub xxx $query "([random_or_query $nEntry])" query |
| 113 } |
| 114 return $query |
| 115 } |
| 116 |
| 117 proc balanced_andor_tree {nEntry} { |
| 118 set tree [balanced_exprtree_structure $nEntry] |
| 119 set node "{[balanced_and_tree $nEntry]}" |
| 120 regsub -all AND $node OR node |
| 121 regsub -all xxx $tree $node tree |
| 122 return $tree |
| 123 } |
| 124 |
| 125 # Test that queries like "1 AND 2 AND 3 AND 4..." are transformed to |
| 126 # balanced trees by FTS. |
| 127 # |
| 128 for {set i 1} {$i < 100} {incr i} { |
| 129 do_test 1.$i { |
| 130 test_fts3expr2 [random_and_query $i] |
| 131 } [balanced_and_tree $i] |
| 132 } |
| 133 |
| 134 # Same again, except with parenthesis inserted at arbitrary points. |
| 135 # |
| 136 for {set i 1} {$i < 100} {incr i} { |
| 137 do_test 2.$i { |
| 138 test_fts3expr2 [random_and_query $i 1] |
| 139 } [balanced_and_tree $i] |
| 140 } |
| 141 |
| 142 # Now attempt to balance two AND trees joined by an OR. |
| 143 # |
| 144 for {set i 1} {$i < 100} {incr i} { |
| 145 do_test 3.$i { |
| 146 test_fts3expr2 "[random_and_query $i 1] OR [random_and_query $i 1]" |
| 147 } [list OR [balanced_and_tree $i] [balanced_and_tree $i]] |
| 148 } |
| 149 |
| 150 # Try trees of AND nodes with leaves that are themselves trees of OR nodes. |
| 151 # |
| 152 for {set i 2} {$i < 64} {incr i 4} { |
| 153 do_test 3.$i { |
| 154 test_fts3expr2 [random_andor_query $i] |
| 155 } [balanced_andor_tree $i] |
| 156 } |
| 157 |
| 158 # These exceed the depth limit. |
| 159 # |
| 160 for {set i 65} {$i < 70} {incr i} { |
| 161 do_test 3.$i { |
| 162 list [catch {test_fts3expr2 [random_andor_query $i]} msg] $msg |
| 163 } {1 {Error parsing expression}} |
| 164 } |
| 165 |
| 166 # This also exceeds the depth limit. |
| 167 # |
| 168 |
| 169 do_test 4.1.1 { |
| 170 set q "1" |
| 171 for {set i 2} {$i < 5000} {incr i} { |
| 172 append q " AND $i" |
| 173 } |
| 174 list [catch {test_fts3expr2 $q} msg] $msg |
| 175 } {1 {Error parsing expression}} |
| 176 do_test 4.1.2 { |
| 177 set q "1" |
| 178 for {set i 2} {$i < 4000} {incr i} { |
| 179 append q " AND $i" |
| 180 } |
| 181 catch {test_fts3expr2 $q} |
| 182 } {0} |
| 183 |
| 184 proc create_toggle_tree {nDepth} { |
| 185 if {$nDepth == 0} { return xxx } |
| 186 set nNew [expr $nDepth-1] |
| 187 if {$nDepth % 2} { |
| 188 return "([create_toggle_tree $nNew]) OR ([create_toggle_tree $nNew])" |
| 189 } |
| 190 return "([create_toggle_tree $nNew]) AND ([create_toggle_tree $nNew])" |
| 191 } |
| 192 |
| 193 do_test 4.2 { |
| 194 list [catch {test_fts3expr2 [create_toggle_tree 17]} msg] $msg |
| 195 } {1 {Error parsing expression}} |
| 196 |
| 197 set query [random_andor_query 12] |
| 198 set result [balanced_andor_tree 12] |
| 199 do_faultsim_test fts3expr3-fault-1 -faults oom-* -body { |
| 200 test_fts3expr2 $::query |
| 201 } -test { |
| 202 faultsim_test_result [list 0 $::result] |
| 203 } |
| 204 |
| 205 set sqlite_fts3_enable_parentheses 0 |
| 206 finish_test |
OLD | NEW |