OLD | NEW |
1 # 2009 August 06 | 1 # 2009 August 06 |
2 # | 2 # |
3 # The author disclaims copyright to this source code. In place of | 3 # The author disclaims copyright to this source code. In place of |
4 # a legal notice, here is a blessing: | 4 # a legal notice, here is a blessing: |
5 # | 5 # |
6 # May you do good and not evil. | 6 # May you do good and not evil. |
7 # May you find forgiveness for yourself and forgive others. | 7 # May you find forgiveness for yourself and forgive others. |
8 # May you share freely, never taking more than you give. | 8 # May you share freely, never taking more than you give. |
9 # | 9 # |
10 #*********************************************************************** | 10 #*********************************************************************** |
11 # | 11 # |
12 # This file implements regression tests for SQLite library. This file | 12 # This file implements regression tests for SQLite library. This file |
13 # implements tests for range and LIKE constraints that use bound variables | 13 # implements tests for range and LIKE constraints that use bound variables |
14 # instead of literal constant arguments. | 14 # instead of literal constant arguments. |
15 # | 15 # |
16 | 16 |
17 set testdir [file dirname $argv0] | 17 set testdir [file dirname $argv0] |
18 source $testdir/tester.tcl | 18 source $testdir/tester.tcl |
19 | 19 |
20 ifcapable !stat2 { | 20 ifcapable !stat4&&!stat3 { |
21 finish_test | 21 finish_test |
22 return | 22 return |
23 } | 23 } |
24 | 24 |
25 #---------------------------------------------------------------------- | 25 #---------------------------------------------------------------------- |
26 # Test Organization: | 26 # Test Organization: |
27 # | 27 # |
28 # analyze3-1.*: Test that the values of bound parameters are considered | 28 # analyze3-1.*: Test that the values of bound parameters are considered |
29 # in the same way as constants when planning queries that | 29 # in the same way as constants when planning queries that |
30 # use range constraints. | 30 # use range constraints. |
31 # | 31 # |
32 # analyze3-2.*: Test that the values of bound parameters are considered | 32 # analyze3-2.*: Test that the values of bound parameters are considered |
33 # in the same way as constants when planning queries that | 33 # in the same way as constants when planning queries that |
34 # use LIKE expressions in the WHERE clause. | 34 # use LIKE expressions in the WHERE clause. |
35 # | 35 # |
36 # analyze3-3.*: Test that binding to a variable does not invalidate the | 36 # analyze3-3.*: Test that binding to a variable does not invalidate the |
37 # query plan when there is no way in which replanning the | 37 # query plan when there is no way in which replanning the |
38 # query may produce a superior outcome. | 38 # query may produce a superior outcome. |
39 # | 39 # |
40 # analyze3-4.*: Test that SQL or authorization callback errors occuring | 40 # analyze3-4.*: Test that SQL or authorization callback errors occuring |
41 # within sqlite3Reprepare() are handled correctly. | 41 # within sqlite3Reprepare() are handled correctly. |
42 # | 42 # |
43 # analyze3-5.*: Check that the query plans of applicable statements are | 43 # analyze3-5.*: Check that the query plans of applicable statements are |
44 # invalidated if the values of SQL parameter are modified | 44 # invalidated if the values of SQL parameter are modified |
45 # using the clear_bindings() or transfer_bindings() APIs. | 45 # using the clear_bindings() or transfer_bindings() APIs. |
| 46 # |
| 47 # analyze3-6.*: Test that the problem fixed by commit [127a5b776d] is fixed. |
46 # | 48 # |
47 | 49 |
48 proc getvar {varname} { uplevel #0 set $varname } | 50 proc getvar {varname} { uplevel #0 set $varname } |
49 db function var getvar | 51 db function var getvar |
50 | 52 |
51 proc eqp {sql {db db}} { | 53 proc eqp {sql {db db}} { |
52 uplevel execsql [list "EXPLAIN QUERY PLAN $sql"] $db | 54 uplevel execsql [list "EXPLAIN QUERY PLAN $sql"] $db |
53 } | 55 } |
54 | 56 |
55 proc sf_execsql {sql {db db}} { | 57 proc sf_execsql {sql {db db}} { |
56 set ::sqlite_search_count 0 | 58 set ::sqlite_search_count 0 |
57 set r [uplevel [list execsql $sql $db]] | 59 set r [uplevel [list execsql $sql $db]] |
58 | 60 |
59 concat $::sqlite_search_count [$db status step] $r | 61 concat $::sqlite_search_count [$db status step] $r |
60 } | 62 } |
61 | 63 |
62 #------------------------------------------------------------------------- | 64 #------------------------------------------------------------------------- |
63 # | 65 # |
64 # analyze3-1.1.1: | 66 # analyze3-1.1.1: |
65 # Create a table with two columns. Populate the first column (affinity | 67 # Create a table with two columns. Populate the first column (affinity |
66 # INTEGER) with integer values from 100 to 1100. Create an index on this | 68 # INTEGER) with integer values from 100 to 1100. Create an index on this |
67 # column. ANALYZE the table. | 69 # column. ANALYZE the table. |
68 # | 70 # |
69 # analyze3-1.1.2 - 3.1.3 | 71 # analyze3-1.1.2 - 3.1.3 |
70 # Show that there are two possible plans for querying the table with | 72 # Show that there are two possible plans for querying the table with |
71 # a range constraint on the indexed column - "full table scan" or "use | 73 # a range constraint on the indexed column - "full table scan" or "use |
72 # the index". When the range is specified using literal values, SQLite | 74 # the index". When the range is specified using literal values, SQLite |
73 # is able to pick the best plan based on the samples in sqlite_stat2. | 75 # is able to pick the best plan based on the samples in sqlite_stat3. |
74 # | 76 # |
75 # analyze3-1.1.4 - 3.1.9 | 77 # analyze3-1.1.4 - 3.1.9 |
76 # Show that using SQL variables produces the same results as using | 78 # Show that using SQL variables produces the same results as using |
77 # literal values to constrain the range scan. | 79 # literal values to constrain the range scan. |
78 # | 80 # |
79 # These tests also check that the compiler code considers column | 81 # These tests also check that the compiler code considers column |
80 # affinities when estimating the number of rows scanned by the "use | 82 # affinities when estimating the number of rows scanned by the "use |
81 # index strategy". | 83 # index strategy". |
82 # | 84 # |
83 do_test analyze3-1.1.1 { | 85 do_test analyze3-1.1.1 { |
84 execsql { | 86 execsql { |
85 BEGIN; | 87 BEGIN; |
86 CREATE TABLE t1(x INTEGER, y); | 88 CREATE TABLE t1(x INTEGER, y); |
87 CREATE INDEX i1 ON t1(x); | 89 CREATE INDEX i1 ON t1(x); |
88 } | 90 } |
89 for {set i 0} {$i < 1000} {incr i} { | 91 for {set i 0} {$i < 1000} {incr i} { |
90 execsql { INSERT INTO t1 VALUES($i+100, $i) } | 92 execsql { INSERT INTO t1 VALUES($i+100, $i) } |
91 } | 93 } |
92 execsql { | 94 execsql { |
93 COMMIT; | 95 COMMIT; |
94 ANALYZE; | 96 ANALYZE; |
95 } | 97 } |
96 } {} | |
97 | 98 |
| 99 ifcapable stat4 { |
| 100 execsql { SELECT count(*)>0 FROM sqlite_stat4; } |
| 101 } else { |
| 102 execsql { SELECT count(*)>0 FROM sqlite_stat3; } |
| 103 } |
| 104 } {1} |
| 105 |
| 106 do_execsql_test analyze3-1.1.x { |
| 107 SELECT count(*) FROM t1 WHERE x>200 AND x<300; |
| 108 SELECT count(*) FROM t1 WHERE x>0 AND x<1100; |
| 109 } {99 1000} |
| 110 |
| 111 # The first of the following two SELECT statements visits 99 rows. So |
| 112 # it is better to use the index. But the second visits every row in |
| 113 # the table (1000 in total) so it is better to do a full-table scan. |
| 114 # |
98 do_eqp_test analyze3-1.1.2 { | 115 do_eqp_test analyze3-1.1.2 { |
99 SELECT sum(y) FROM t1 WHERE x>200 AND x<300 | 116 SELECT sum(y) FROM t1 WHERE x>200 AND x<300 |
100 } {0 0 0 {SEARCH TABLE t1 USING INDEX i1 (x>? AND x<?) (~100 rows)}} | 117 } {0 0 0 {SEARCH TABLE t1 USING INDEX i1 (x>? AND x<?)}} |
101 do_eqp_test analyze3-1.1.3 { | 118 do_eqp_test analyze3-1.1.3 { |
102 SELECT sum(y) FROM t1 WHERE x>0 AND x<1100 | 119 SELECT sum(y) FROM t1 WHERE x>0 AND x<1100 |
103 } {0 0 0 {SCAN TABLE t1 (~111 rows)}} | 120 } {0 0 0 {SCAN TABLE t1}} |
104 | 121 |
105 do_test analyze3-1.1.4 { | 122 do_test analyze3-1.1.4 { |
106 sf_execsql { SELECT sum(y) FROM t1 WHERE x>200 AND x<300 } | 123 sf_execsql { SELECT sum(y) FROM t1 WHERE x>200 AND x<300 } |
107 } {199 0 14850} | 124 } {199 0 14850} |
108 do_test analyze3-1.1.5 { | 125 do_test analyze3-1.1.5 { |
109 set l [string range "200" 0 end] | 126 set l [string range "200" 0 end] |
110 set u [string range "300" 0 end] | 127 set u [string range "300" 0 end] |
111 sf_execsql { SELECT sum(y) FROM t1 WHERE x>$l AND x<$u } | 128 sf_execsql { SELECT sum(y) FROM t1 WHERE x>$l AND x<$u } |
112 } {199 0 14850} | 129 } {199 0 14850} |
113 do_test analyze3-1.1.6 { | 130 do_test analyze3-1.1.6 { |
(...skipping 23 matching lines...) Expand all Loading... |
137 do_test analyze3-1.2.1 { | 154 do_test analyze3-1.2.1 { |
138 execsql { | 155 execsql { |
139 BEGIN; | 156 BEGIN; |
140 CREATE TABLE t2(x TEXT, y); | 157 CREATE TABLE t2(x TEXT, y); |
141 INSERT INTO t2 SELECT * FROM t1; | 158 INSERT INTO t2 SELECT * FROM t1; |
142 CREATE INDEX i2 ON t2(x); | 159 CREATE INDEX i2 ON t2(x); |
143 COMMIT; | 160 COMMIT; |
144 ANALYZE; | 161 ANALYZE; |
145 } | 162 } |
146 } {} | 163 } {} |
| 164 do_execsql_test analyze3-2.1.x { |
| 165 SELECT count(*) FROM t2 WHERE x>1 AND x<2; |
| 166 SELECT count(*) FROM t2 WHERE x>0 AND x<99; |
| 167 } {200 990} |
147 do_eqp_test analyze3-1.2.2 { | 168 do_eqp_test analyze3-1.2.2 { |
148 SELECT sum(y) FROM t2 WHERE x>1 AND x<2 | 169 SELECT sum(y) FROM t2 WHERE x>1 AND x<2 |
149 } {0 0 0 {SEARCH TABLE t2 USING INDEX i2 (x>? AND x<?) (~200 rows)}} | 170 } {0 0 0 {SEARCH TABLE t2 USING INDEX i2 (x>? AND x<?)}} |
150 do_eqp_test analyze3-1.2.3 { | 171 do_eqp_test analyze3-1.2.3 { |
151 SELECT sum(y) FROM t2 WHERE x>0 AND x<99 | 172 SELECT sum(y) FROM t2 WHERE x>0 AND x<99 |
152 } {0 0 0 {SCAN TABLE t2 (~111 rows)}} | 173 } {0 0 0 {SCAN TABLE t2}} |
| 174 |
153 do_test analyze3-1.2.4 { | 175 do_test analyze3-1.2.4 { |
154 sf_execsql { SELECT sum(y) FROM t2 WHERE x>12 AND x<20 } | 176 sf_execsql { SELECT sum(y) FROM t2 WHERE x>12 AND x<20 } |
155 } {161 0 4760} | 177 } {161 0 4760} |
156 do_test analyze3-1.2.5 { | 178 do_test analyze3-1.2.5 { |
157 set l [string range "12" 0 end] | 179 set l [string range "12" 0 end] |
158 set u [string range "20" 0 end] | 180 set u [string range "20" 0 end] |
159 sf_execsql {SELECT typeof($l), typeof($u), sum(y) FROM t2 WHERE x>$l AND x<$u} | 181 sf_execsql {SELECT typeof($l), typeof($u), sum(y) FROM t2 WHERE x>$l AND x<$u} |
160 } {161 0 text text 4760} | 182 } {161 0 text text 4760} |
161 do_test analyze3-1.2.6 { | 183 do_test analyze3-1.2.6 { |
162 set l [expr int(12)] | 184 set l [expr int(12)] |
(...skipping 21 matching lines...) Expand all Loading... |
184 do_test analyze3-1.3.1 { | 206 do_test analyze3-1.3.1 { |
185 execsql { | 207 execsql { |
186 BEGIN; | 208 BEGIN; |
187 CREATE TABLE t3(y TEXT, x INTEGER); | 209 CREATE TABLE t3(y TEXT, x INTEGER); |
188 INSERT INTO t3 SELECT y, x FROM t1; | 210 INSERT INTO t3 SELECT y, x FROM t1; |
189 CREATE INDEX i3 ON t3(x); | 211 CREATE INDEX i3 ON t3(x); |
190 COMMIT; | 212 COMMIT; |
191 ANALYZE; | 213 ANALYZE; |
192 } | 214 } |
193 } {} | 215 } {} |
| 216 do_execsql_test analyze3-1.3.x { |
| 217 SELECT count(*) FROM t3 WHERE x>200 AND x<300; |
| 218 SELECT count(*) FROM t3 WHERE x>0 AND x<1100 |
| 219 } {99 1000} |
194 do_eqp_test analyze3-1.3.2 { | 220 do_eqp_test analyze3-1.3.2 { |
195 SELECT sum(y) FROM t3 WHERE x>200 AND x<300 | 221 SELECT sum(y) FROM t3 WHERE x>200 AND x<300 |
196 } {0 0 0 {SEARCH TABLE t3 USING INDEX i3 (x>? AND x<?) (~100 rows)}} | 222 } {0 0 0 {SEARCH TABLE t3 USING INDEX i3 (x>? AND x<?)}} |
197 do_eqp_test analyze3-1.3.3 { | 223 do_eqp_test analyze3-1.3.3 { |
198 SELECT sum(y) FROM t3 WHERE x>0 AND x<1100 | 224 SELECT sum(y) FROM t3 WHERE x>0 AND x<1100 |
199 } {0 0 0 {SCAN TABLE t3 (~111 rows)}} | 225 } {0 0 0 {SCAN TABLE t3}} |
200 | 226 |
201 do_test analyze3-1.3.4 { | 227 do_test analyze3-1.3.4 { |
202 sf_execsql { SELECT sum(y) FROM t3 WHERE x>200 AND x<300 } | 228 sf_execsql { SELECT sum(y) FROM t3 WHERE x>200 AND x<300 } |
203 } {199 0 14850} | 229 } {199 0 14850} |
204 do_test analyze3-1.3.5 { | 230 do_test analyze3-1.3.5 { |
205 set l [string range "200" 0 end] | 231 set l [string range "200" 0 end] |
206 set u [string range "300" 0 end] | 232 set u [string range "300" 0 end] |
207 sf_execsql { SELECT sum(y) FROM t3 WHERE x>$l AND x<$u } | 233 sf_execsql { SELECT sum(y) FROM t3 WHERE x>$l AND x<$u } |
208 } {199 0 14850} | 234 } {199 0 14850} |
209 do_test analyze3-1.3.6 { | 235 do_test analyze3-1.3.6 { |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
241 set t "" | 267 set t "" |
242 append t [lindex {a b c d e f g h i j} [expr $i/100]] | 268 append t [lindex {a b c d e f g h i j} [expr $i/100]] |
243 append t [lindex {a b c d e f g h i j} [expr ($i/10)%10]] | 269 append t [lindex {a b c d e f g h i j} [expr ($i/10)%10]] |
244 append t [lindex {a b c d e f g h i j} [expr ($i%10)]] | 270 append t [lindex {a b c d e f g h i j} [expr ($i%10)]] |
245 execsql { INSERT INTO t1 VALUES($i, $t) } | 271 execsql { INSERT INTO t1 VALUES($i, $t) } |
246 } | 272 } |
247 execsql COMMIT | 273 execsql COMMIT |
248 } {} | 274 } {} |
249 do_eqp_test analyze3-2.2 { | 275 do_eqp_test analyze3-2.2 { |
250 SELECT count(a) FROM t1 WHERE b LIKE 'a%' | 276 SELECT count(a) FROM t1 WHERE b LIKE 'a%' |
251 } {0 0 0 {SEARCH TABLE t1 USING INDEX i1 (b>? AND b<?) (~30000 rows)}} | 277 } {0 0 0 {SEARCH TABLE t1 USING INDEX i1 (b>? AND b<?)}} |
252 do_eqp_test analyze3-2.3 { | 278 do_eqp_test analyze3-2.3 { |
253 SELECT count(a) FROM t1 WHERE b LIKE '%a' | 279 SELECT count(a) FROM t1 WHERE b LIKE '%a' |
254 } {0 0 0 {SCAN TABLE t1 (~500000 rows)}} | 280 } {0 0 0 {SCAN TABLE t1}} |
255 | 281 |
256 do_test analyze3-2.4 { | 282 do_test analyze3-2.4 { |
257 sf_execsql { SELECT count(*) FROM t1 WHERE b LIKE 'a%' } | 283 sf_execsql { SELECT count(*) FROM t1 WHERE b LIKE 'a%' } |
258 } {101 0 100} | 284 } {101 0 100} |
259 do_test analyze3-2.5 { | 285 do_test analyze3-2.5 { |
260 sf_execsql { SELECT count(*) FROM t1 WHERE b LIKE '%a' } | 286 sf_execsql { SELECT count(*) FROM t1 WHERE b LIKE '%a' } |
261 } {999 999 100} | 287 } {999 999 100} |
262 | 288 |
263 do_test analyze3-2.4 { | 289 do_test analyze3-2.4 { |
264 set like "a%" | 290 set like "a%" |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
303 BEGIN; | 329 BEGIN; |
304 CREATE TABLE t1(a, b, c); | 330 CREATE TABLE t1(a, b, c); |
305 CREATE INDEX i1 ON t1(b); | 331 CREATE INDEX i1 ON t1(b); |
306 } | 332 } |
307 for {set i 0} {$i < 100} {incr i} { | 333 for {set i 0} {$i < 100} {incr i} { |
308 execsql { INSERT INTO t1 VALUES($i, $i, $i) } | 334 execsql { INSERT INTO t1 VALUES($i, $i, $i) } |
309 } | 335 } |
310 execsql COMMIT | 336 execsql COMMIT |
311 execsql ANALYZE | 337 execsql ANALYZE |
312 } {} | 338 } {} |
313 | |
314 do_test analyze3-3.2.1 { | 339 do_test analyze3-3.2.1 { |
315 set S [sqlite3_prepare_v2 db "SELECT * FROM t1 WHERE b>?" -1 dummy] | 340 set S [sqlite3_prepare_v2 db "SELECT * FROM t1 WHERE b>?" -1 dummy] |
316 sqlite3_expired $S | 341 sqlite3_expired $S |
317 } {0} | 342 } {0} |
318 do_test analyze3-3.2.2 { | 343 do_test analyze3-3.2.2 { |
319 sqlite3_bind_text $S 1 "abc" 3 | 344 sqlite3_bind_text $S 1 "abc" 3 |
320 sqlite3_expired $S | 345 sqlite3_expired $S |
321 } {1} | 346 } {1} |
322 do_test analyze3-3.2.4 { | 347 do_test analyze3-3.2.4 { |
323 sqlite3_finalize $S | 348 sqlite3_finalize $S |
324 } {SQLITE_OK} | 349 } {SQLITE_OK} |
325 | 350 |
326 do_test analyze3-3.2.5 { | 351 do_test analyze3-3.2.5 { |
327 set S [sqlite3_prepare_v2 db "SELECT * FROM t1 WHERE b=?" -1 dummy] | 352 set S [sqlite3_prepare_v2 db "SELECT * FROM t1 WHERE b=?" -1 dummy] |
328 sqlite3_expired $S | 353 sqlite3_expired $S |
329 } {0} | 354 } {0} |
330 do_test analyze3-3.2.6 { | 355 do_test analyze3-3.2.6 { |
331 sqlite3_bind_text $S 1 "abc" 3 | 356 sqlite3_bind_text $S 1 "abc" 3 |
332 sqlite3_expired $S | 357 sqlite3_expired $S |
333 } {0} | 358 } {1} |
334 do_test analyze3-3.2.7 { | 359 do_test analyze3-3.2.7 { |
335 sqlite3_finalize $S | 360 sqlite3_finalize $S |
336 } {SQLITE_OK} | 361 } {SQLITE_OK} |
337 | 362 |
338 do_test analyze3-3.4.1 { | 363 do_test analyze3-3.4.1 { |
339 set S [sqlite3_prepare_v2 db "SELECT * FROM t1 WHERE a=? AND b>?" -1 dummy] | 364 set S [sqlite3_prepare_v2 db "SELECT * FROM t1 WHERE a=? AND b>?" -1 dummy] |
340 sqlite3_expired $S | 365 sqlite3_expired $S |
341 } {0} | 366 } {0} |
342 do_test analyze3-3.4.2 { | 367 do_test analyze3-3.4.2 { |
343 sqlite3_bind_text $S 1 "abc" 3 | 368 sqlite3_bind_text $S 1 "abc" 3 |
(...skipping 261 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
605 while { "SQLITE_ROW" == [sqlite3_step $S1] } { | 630 while { "SQLITE_ROW" == [sqlite3_step $S1] } { |
606 lappend R [sqlite3_column_text $S1 0] | 631 lappend R [sqlite3_column_text $S1 0] |
607 } | 632 } |
608 concat [sqlite3_reset $S1] $R | 633 concat [sqlite3_reset $S1] $R |
609 } {SQLITE_OK aaa abb acc} | 634 } {SQLITE_OK aaa abb acc} |
610 do_test analyze3-5.1.3 { | 635 do_test analyze3-5.1.3 { |
611 sqlite3_finalize $S2 | 636 sqlite3_finalize $S2 |
612 sqlite3_finalize $S1 | 637 sqlite3_finalize $S1 |
613 } {SQLITE_OK} | 638 } {SQLITE_OK} |
614 | 639 |
| 640 #------------------------------------------------------------------------- |
| 641 |
| 642 do_test analyze3-6.1 { |
| 643 execsql { DROP TABLE IF EXISTS t1 } |
| 644 execsql BEGIN |
| 645 execsql { CREATE TABLE t1(a, b, c) } |
| 646 for {set i 0} {$i < 1000} {incr i} { |
| 647 execsql "INSERT INTO t1 VALUES([expr $i/100], 'x', [expr $i/10])" |
| 648 } |
| 649 execsql { |
| 650 CREATE INDEX i1 ON t1(a, b); |
| 651 CREATE INDEX i2 ON t1(c); |
| 652 } |
| 653 execsql COMMIT |
| 654 execsql ANALYZE |
| 655 } {} |
| 656 |
| 657 do_eqp_test analyze3-6-3 { |
| 658 SELECT * FROM t1 WHERE a = 5 AND c = 13; |
| 659 } {0 0 0 {SEARCH TABLE t1 USING INDEX i2 (c=?)}} |
| 660 |
| 661 do_eqp_test analyze3-6-2 { |
| 662 SELECT * FROM t1 WHERE a = 5 AND b > 'w' AND c = 13; |
| 663 } {0 0 0 {SEARCH TABLE t1 USING INDEX i2 (c=?)}} |
| 664 |
615 finish_test | 665 finish_test |
OLD | NEW |